Skip to content

Commit

Permalink
Have Header Object follow the structure of the Parameter Object (#355)
Browse files Browse the repository at this point in the history
  • Loading branch information
fenollp authored May 20, 2021
1 parent 7be9302 commit 56338d2
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 34 deletions.
74 changes: 61 additions & 13 deletions openapi3/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package openapi3

import (
"context"
"errors"
"fmt"

"github.com/getkin/kin-openapi/jsoninfo"
Expand All @@ -24,17 +25,10 @@ func (h Headers) JSONLookup(token string) (interface{}, error) {
return ref.Value, nil
}

// Header is specified by OpenAPI/Swagger 3.0 standard.
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#headerObject
type Header struct {
ExtensionProps

// Optional description. Should use CommonMark syntax.
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *SchemaRef `json:"schema,omitempty" yaml:"schema,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Examples Examples `json:"examples,omitempty" yaml:"examples,omitempty"`
Content Content `json:"content,omitempty" yaml:"content,omitempty"`
Parameter
}

var _ jsonpointer.JSONPointable = (*Header)(nil)
Expand All @@ -43,10 +37,52 @@ func (value *Header) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, value)
}

// SerializationMethod returns a header's serialization method.
func (value *Header) SerializationMethod() (*SerializationMethod, error) {
style := value.Style
if style == "" {
style = SerializationSimple
}
explode := false
if value.Explode != nil {
explode = *value.Explode
}
return &SerializationMethod{Style: style, Explode: explode}, nil
}

func (value *Header) Validate(ctx context.Context) error {
if v := value.Schema; v != nil {
if err := v.Validate(ctx); err != nil {
return err
if value.Name != "" {
return errors.New("header 'name' MUST NOT be specified, it is given in the corresponding headers map")
}
if value.In != "" {
return errors.New("header 'in' MUST NOT be specified, it is implicitly in header")
}

// Validate a parameter's serialization method.
sm, err := value.SerializationMethod()
if err != nil {
return err
}
if smSupported := false ||
sm.Style == SerializationSimple && !sm.Explode ||
sm.Style == SerializationSimple && sm.Explode; !smSupported {
e := fmt.Errorf("serialization method with style=%q and explode=%v is not supported by a header parameter", sm.Style, sm.Explode)
return fmt.Errorf("header schema is invalid: %v", e)
}

if (value.Schema == nil) == (value.Content == nil) {
e := fmt.Errorf("parameter must contain exactly one of content and schema: %v", value)
return fmt.Errorf("header schema is invalid: %v", e)
}
if schema := value.Schema; schema != nil {
if err := schema.Validate(ctx); err != nil {
return fmt.Errorf("header schema is invalid: %v", err)
}
}

if content := value.Content; content != nil {
if err := content.Validate(ctx); err != nil {
return fmt.Errorf("header content is invalid: %v", err)
}
}
return nil
Expand All @@ -61,8 +97,20 @@ func (value Header) JSONLookup(token string) (interface{}, error) {
}
return value.Schema.Value, nil
}
case "name":
return value.Name, nil
case "in":
return value.In, nil
case "description":
return value.Description, nil
case "style":
return value.Style, nil
case "explode":
return value.Explode, nil
case "allowEmptyValue":
return value.AllowEmptyValue, nil
case "allowReserved":
return value.AllowReserved, nil
case "deprecated":
return value.Deprecated, nil
case "required":
Expand Down
11 changes: 8 additions & 3 deletions openapi3/openapi3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ components:
someSchema:
description: Some schema
headers:
otherHeader: {}
otherHeader:
schema: {type: string}
someHeader:
"$ref": "#/components/headers/otherHeader"
examples:
Expand Down Expand Up @@ -207,7 +208,11 @@ var specJSON = []byte(`
}
},
"headers": {
"otherHeader": {},
"otherHeader": {
"schema": {
"type": "string"
}
},
"someHeader": {
"$ref": "#/components/headers/otherHeader"
}
Expand Down Expand Up @@ -317,7 +322,7 @@ func spec() *T {
Ref: "#/components/headers/otherHeader",
},
"otherHeader": {
Value: &Header{},
Value: &Header{Parameter{Schema: &SchemaRef{Value: NewStringSchema()}}},
},
},
Examples: map[string]*ExampleRef{
Expand Down
38 changes: 20 additions & 18 deletions openapi3/parameter.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ func (value Parameters) Validate(ctx context.Context) error {
}

// Parameter is specified by OpenAPI/Swagger 3.0 standard.
// See https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#parameterObject
type Parameter struct {
ExtensionProps
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Expand Down Expand Up @@ -167,42 +168,42 @@ func (parameter *Parameter) UnmarshalJSON(data []byte) error {
return jsoninfo.UnmarshalStrictStruct(data, parameter)
}

func (parameter Parameter) JSONLookup(token string) (interface{}, error) {
func (value Parameter) JSONLookup(token string) (interface{}, error) {
switch token {
case "schema":
if parameter.Schema != nil {
if parameter.Schema.Ref != "" {
return &Ref{Ref: parameter.Schema.Ref}, nil
if value.Schema != nil {
if value.Schema.Ref != "" {
return &Ref{Ref: value.Schema.Ref}, nil
}
return parameter.Schema.Value, nil
return value.Schema.Value, nil
}
case "name":
return parameter.Name, nil
return value.Name, nil
case "in":
return parameter.In, nil
return value.In, nil
case "description":
return parameter.Description, nil
return value.Description, nil
case "style":
return parameter.Style, nil
return value.Style, nil
case "explode":
return parameter.Explode, nil
return value.Explode, nil
case "allowEmptyValue":
return parameter.AllowEmptyValue, nil
return value.AllowEmptyValue, nil
case "allowReserved":
return parameter.AllowReserved, nil
return value.AllowReserved, nil
case "deprecated":
return parameter.Deprecated, nil
return value.Deprecated, nil
case "required":
return parameter.Required, nil
return value.Required, nil
case "example":
return parameter.Example, nil
return value.Example, nil
case "examples":
return parameter.Examples, nil
return value.Examples, nil
case "content":
return parameter.Content, nil
return value.Content, nil
}

v, _, err := jsonpointer.GetForToken(parameter.ExtensionProps, token)
v, _, err := jsonpointer.GetForToken(value.ExtensionProps, token)
return v, err
}

Expand Down Expand Up @@ -294,6 +295,7 @@ func (value *Parameter) Validate(ctx context.Context) error {
return fmt.Errorf("parameter %q schema is invalid: %v", value.Name, err)
}
}

if content := value.Content; content != nil {
if err := content.Validate(ctx); err != nil {
return fmt.Errorf("parameter %q content is invalid: %v", value.Name, err)
Expand Down

0 comments on commit 56338d2

Please sign in to comment.