Files
libopenapi/datamodel/low/v3/header.go
Dave Shanley b42e35f2b7 Wired up multi-version handling patterns
Designs for handling multiple versions of objects have been set, seems clean and scalable. Generic functions for handling maps has been added also, which will cut down time moving forward.
2022-11-18 11:00:34 -05:00

231 lines
6.5 KiB
Go

// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
// SPDX-License-Identifier: MIT
package v3
import (
"crypto/sha256"
"fmt"
"github.com/pb33f/libopenapi/datamodel/low"
"github.com/pb33f/libopenapi/datamodel/low/base"
"github.com/pb33f/libopenapi/index"
"github.com/pb33f/libopenapi/utils"
"gopkg.in/yaml.v3"
"strings"
)
// Header represents a low-level OpenAPI 3+ Header object.
// - https://spec.openapis.org/oas/v3.1.0#header-object
type Header struct {
Description low.NodeReference[string]
Required low.NodeReference[bool]
Deprecated low.NodeReference[bool]
AllowEmptyValue low.NodeReference[bool]
Style low.NodeReference[string]
Explode low.NodeReference[bool]
AllowReserved low.NodeReference[bool]
Schema low.NodeReference[*base.SchemaProxy]
Example low.NodeReference[any]
Examples low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]
Content low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]
Extensions map[low.KeyReference[string]]low.ValueReference[any]
}
// FindExtension will attempt to locate an extension with the supplied name
func (h *Header) FindExtension(ext string) *low.ValueReference[any] {
return low.FindItemInMap[any](ext, h.Extensions)
}
// FindExample will attempt to locate an Example with a specified name
func (h *Header) FindExample(eType string) *low.ValueReference[*base.Example] {
return low.FindItemInMap[*base.Example](eType, h.Examples.Value)
}
// FindContent will attempt to locate a MediaType definition, with a specified name
func (h *Header) FindContent(ext string) *low.ValueReference[*MediaType] {
return low.FindItemInMap[*MediaType](ext, h.Content.Value)
}
// Hash will return a consistent SHA256 Hash of the Header object
func (h *Header) Hash() [32]byte {
var f []string
if h.Description.Value != "" {
f = append(f, h.Description.Value)
}
f = append(f, fmt.Sprint(h.Required.Value))
f = append(f, fmt.Sprint(h.Deprecated.Value))
f = append(f, fmt.Sprint(h.AllowEmptyValue.Value))
if h.Style.Value != "" {
f = append(f, h.Style.Value)
}
f = append(f, fmt.Sprint(h.Explode.Value))
f = append(f, fmt.Sprint(h.AllowReserved.Value))
if h.Schema.Value != nil {
f = append(f, fmt.Sprint(h.Schema.Value.Schema().Hash()))
}
if h.Example.Value != nil {
f = append(f, fmt.Sprint(h.Example.Value))
}
if len(h.Examples.Value) > 0 {
for k := range h.Examples.Value {
f = append(f, fmt.Sprintf("%s-%x", k.Value, h.Examples.Value[k].Value.Hash()))
}
}
if len(h.Content.Value) > 0 {
for k := range h.Content.Value {
f = append(f, fmt.Sprintf("%s-%x", k.Value, h.Content.Value[k].Value.Hash()))
}
}
for k := range h.Extensions {
f = append(f, fmt.Sprintf("%s-%v", k.Value, h.Extensions[k].Value))
}
return sha256.Sum256([]byte(strings.Join(f, "|")))
}
// Build will extract extensions, examples, schema and content/media types from node.
func (h *Header) Build(root *yaml.Node, idx *index.SpecIndex) error {
h.Extensions = low.ExtractExtensions(root)
// handle example if set.
_, expLabel, expNode := utils.FindKeyNodeFull(base.ExampleLabel, root.Content)
if expNode != nil {
h.Example = low.ExtractExample(expNode, expLabel)
}
// handle examples if set.
exps, expsL, expsN, eErr := low.ExtractMap[*base.Example](base.ExamplesLabel, root, idx)
if eErr != nil {
return eErr
}
if exps != nil {
h.Examples = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*base.Example]]{
Value: exps,
KeyNode: expsL,
ValueNode: expsN,
}
}
// handle schema
sch, sErr := base.ExtractSchema(root, idx)
if sErr != nil {
return sErr
}
if sch != nil {
h.Schema = *sch
}
// handle content, if set.
con, cL, cN, cErr := low.ExtractMap[*MediaType](ContentLabel, root, idx)
if cErr != nil {
return cErr
}
h.Content = low.NodeReference[map[low.KeyReference[string]]low.ValueReference[*MediaType]]{
Value: con,
KeyNode: cL,
ValueNode: cN,
}
return nil
}
// IsHeader compliance methods.
func (h *Header) GetType() *low.NodeReference[string] {
return nil // not implemented
}
func (h *Header) GetDescription() *low.NodeReference[string] {
return &h.Description
}
func (h *Header) GetRequired() *low.NodeReference[bool] {
return &h.Required
}
func (h *Header) GetDeprecated() *low.NodeReference[bool] {
return &h.Deprecated
}
func (h *Header) GetAllowEmptyValue() *low.NodeReference[bool] {
return &h.AllowEmptyValue
}
func (h *Header) GetSchema() *low.NodeReference[any] {
i := low.NodeReference[any]{
KeyNode: h.Schema.KeyNode,
ValueNode: h.Schema.ValueNode,
Value: h.Schema.KeyNode,
}
return &i
}
func (h *Header) GetFormat() *low.NodeReference[string] {
return nil
}
func (h *Header) GetItems() *low.NodeReference[any] {
return nil
}
func (h *Header) GetStyle() *low.NodeReference[string] {
return &h.Style
}
func (h *Header) GetCollectionFormat() *low.NodeReference[string] {
return nil
}
func (h *Header) GetDefault() *low.NodeReference[any] {
return nil
}
func (h *Header) GetAllowReserved() *low.NodeReference[bool] {
return &h.AllowReserved
}
func (h *Header) GetExplode() *low.NodeReference[bool] {
return &h.Explode
}
func (h *Header) GetMaximum() *low.NodeReference[int] {
return nil
}
func (h *Header) GetExclusiveMaximum() *low.NodeReference[bool] {
return nil
}
func (h *Header) GetMinimum() *low.NodeReference[int] {
return nil
}
func (h *Header) GetExclusiveMinimum() *low.NodeReference[bool] {
return nil
}
func (h *Header) GetMaxLength() *low.NodeReference[int] {
return nil
}
func (h *Header) GetMinLength() *low.NodeReference[int] {
return nil
}
func (h *Header) GetPattern() *low.NodeReference[string] {
return nil
}
func (h *Header) GetMaxItems() *low.NodeReference[int] {
return nil
}
func (h *Header) GetMinItems() *low.NodeReference[int] {
return nil
}
func (h *Header) GetUniqueItems() *low.NodeReference[bool] {
return nil
}
func (h *Header) GetEnum() *low.NodeReference[[]low.ValueReference[string]] {
return nil
}
func (h *Header) GetMultipleOf() *low.NodeReference[int] {
return nil
}
func (h *Header) GetExample() *low.NodeReference[any] {
return &h.Example
}
func (h *Header) GetExamples() *low.NodeReference[any] {
i := low.NodeReference[any]{
KeyNode: h.Examples.KeyNode,
ValueNode: h.Examples.ValueNode,
Value: h.Examples.KeyNode,
}
return &i
}
func (h *Header) GetContent() *low.NodeReference[any] {
c := low.NodeReference[any]{
KeyNode: h.Content.KeyNode,
ValueNode: h.Content.ValueNode,
Value: h.Content.Value,
}
return &c
}