From cea6dc6b0b30762a35ecaa76920eb985457f3fd2 Mon Sep 17 00:00:00 2001 From: Sergey Vilgelm Date: Mon, 31 Jan 2022 19:09:16 -0800 Subject: [PATCH 1/2] openapi2conv: Convert response headers v2 <-> v3 conversion of the Response.Headers objects --- openapi2conv/openapi2_conv.go | 57 ++++++++++++++++++++++++++++++ openapi2conv/openapi2_conv_test.go | 19 ++++++++-- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/openapi2conv/openapi2_conv.go b/openapi2conv/openapi2_conv.go index 04cb18d2e..b7dd903c2 100644 --- a/openapi2conv/openapi2_conv.go +++ b/openapi2conv/openapi2_conv.go @@ -424,9 +424,33 @@ func ToV3Response(response *openapi2.Response) (*openapi3.ResponseRef, error) { if schemaRef := response.Schema; schemaRef != nil { result.WithJSONSchemaRef(ToV3SchemaRef(schemaRef)) } + if headers := response.Headers; len(headers) > 0 { + result.Headers = ToV3Headers(headers) + } return &openapi3.ResponseRef{Value: result}, nil } +func ToV3Headers(defs map[string]*openapi2.Header) openapi3.Headers { + headers := make(openapi3.Headers) + for name, header := range defs { + stripNonCustomExtensions(header.Extensions) + if ref := header.Ref; ref != "" { + headers[name] = &openapi3.HeaderRef{Ref: ToV3Ref(ref)} + } else { + headers[name] = &openapi3.HeaderRef{Value: &openapi3.Header{ + Parameter: openapi3.Parameter{ + ExtensionProps: header.ExtensionProps, + Description: header.Description, + Schema: &openapi3.SchemaRef{Value: &openapi3.Schema{ + Type: header.Type, + }}, + }, + }} + } + } + return headers +} + func ToV3Schemas(defs map[string]*openapi3.SchemaRef) map[string]*openapi3.SchemaRef { schemas := make(map[string]*openapi3.SchemaRef, len(defs)) for name, schema := range defs { @@ -654,6 +678,7 @@ func FromV3(doc3 *openapi3.T) (*openapi2.T, error) { doc2.SecurityDefinitions = doc2SecuritySchemes } doc2.Security = FromV3SecurityRequirements(doc3.Security) + return doc2, nil } @@ -1048,9 +1073,41 @@ func FromV3Response(ref *openapi3.ResponseRef, components *openapi3.Components) result.Schema, _ = FromV3SchemaRef(ct.Schema, components) } } + if headers := response.Headers; len(headers) > 0 { + result.Headers = FromV3Headers(headers, components) + } return result, nil } +func FromV3Headers(defs openapi3.Headers, components *openapi3.Components) map[string]*openapi2.Header { + headers := make(map[string]*openapi2.Header) + for name, header := range defs { + if ref := header.Ref; ref != "" { + headers[name] = &openapi2.Header{Ref: FromV3Ref(ref)} + } else { + stripNonCustomExtensions(header.Value.Extensions) + var headerType string + if ref := header.Value.Schema.Ref; ref != "" { + name := getParameterNameFromNewRef(ref) + if val, ok := components.Schemas[name]; ok { + headerType = val.Value.Type + } + } else { + headerType = header.Value.Schema.Value.Type + } + + headers[name] = &openapi2.Header{ + ExtensionProps: header.Value.ExtensionProps, + Description: header.Value.Description, + Type: headerType, + } + + } + } + + return headers +} + func FromV3SecurityScheme(doc3 *openapi3.T, ref *openapi3.SecuritySchemeRef) (*openapi2.SecurityScheme, error) { securityScheme := ref.Value if securityScheme == nil { diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go index f8f287836..582525563 100644 --- a/openapi2conv/openapi2_conv_test.go +++ b/openapi2conv/openapi2_conv_test.go @@ -5,9 +5,10 @@ import ( "encoding/json" "testing" + "github.com/stretchr/testify/require" + "github.com/getkin/kin-openapi/openapi2" "github.com/getkin/kin-openapi/openapi3" - "github.com/stretchr/testify/require" ) func TestConvOpenAPIV3ToV2(t *testing.T) { @@ -179,6 +180,12 @@ const exampleV2 = ` "$ref": "#/definitions/Item" }, "type": "array" + }, + "headers": { + "ETag": { + "description": "The ETag (or entity tag) HTTP response header is an identifier for a specific version of a resource.", + "type": "string" + } } }, "404": { @@ -543,7 +550,15 @@ const exampleV3 = ` } } }, - "description": "ok" + "description": "ok", + "headers": { + "ETag": { + "description": "The ETag (or entity tag) HTTP response header is an identifier for a specific version of a resource.", + "schema": { + "type": "string" + } + } + } }, "404": { "description": "404 response" From a8f14c6a51393363888d6ed2f9da9d67e1bf0dce Mon Sep 17 00:00:00 2001 From: Sergey Vilgelm Date: Wed, 2 Feb 2022 13:19:29 -0800 Subject: [PATCH 2/2] openapi2: Use Parameter as body for Header struct --- openapi2/openapi2.go | 5 +-- openapi2conv/openapi2_conv.go | 53 +++++++++++------------------- openapi2conv/openapi2_conv_test.go | 6 ++-- 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/openapi2/openapi2.go b/openapi2/openapi2.go index 0d8c07228..de9247f67 100644 --- a/openapi2/openapi2.go +++ b/openapi2/openapi2.go @@ -232,10 +232,7 @@ func (response *Response) UnmarshalJSON(data []byte) error { } type Header struct { - openapi3.ExtensionProps - Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - Type string `json:"type,omitempty" yaml:"type,omitempty"` + Parameter } func (header *Header) MarshalJSON() ([]byte, error) { diff --git a/openapi2conv/openapi2_conv.go b/openapi2conv/openapi2_conv.go index b7dd903c2..4177f1f55 100644 --- a/openapi2conv/openapi2_conv.go +++ b/openapi2conv/openapi2_conv.go @@ -431,20 +431,16 @@ func ToV3Response(response *openapi2.Response) (*openapi3.ResponseRef, error) { } func ToV3Headers(defs map[string]*openapi2.Header) openapi3.Headers { - headers := make(openapi3.Headers) + headers := make(openapi3.Headers, len(defs)) for name, header := range defs { - stripNonCustomExtensions(header.Extensions) + header.In = "" + header.Name = "" if ref := header.Ref; ref != "" { headers[name] = &openapi3.HeaderRef{Ref: ToV3Ref(ref)} } else { + parameter, _, _, _ := ToV3Parameter(nil, &header.Parameter, nil) headers[name] = &openapi3.HeaderRef{Value: &openapi3.Header{ - Parameter: openapi3.Parameter{ - ExtensionProps: header.ExtensionProps, - Description: header.Description, - Schema: &openapi3.SchemaRef{Value: &openapi3.Schema{ - Type: header.Type, - }}, - }, + Parameter: *parameter.Value, }} } } @@ -1074,38 +1070,27 @@ func FromV3Response(ref *openapi3.ResponseRef, components *openapi3.Components) } } if headers := response.Headers; len(headers) > 0 { - result.Headers = FromV3Headers(headers, components) + var err error + if result.Headers, err = FromV3Headers(headers, components); err != nil { + return nil, err + } } return result, nil } -func FromV3Headers(defs openapi3.Headers, components *openapi3.Components) map[string]*openapi2.Header { - headers := make(map[string]*openapi2.Header) +func FromV3Headers(defs openapi3.Headers, components *openapi3.Components) (map[string]*openapi2.Header, error) { + headers := make(map[string]*openapi2.Header, len(defs)) for name, header := range defs { - if ref := header.Ref; ref != "" { - headers[name] = &openapi2.Header{Ref: FromV3Ref(ref)} - } else { - stripNonCustomExtensions(header.Value.Extensions) - var headerType string - if ref := header.Value.Schema.Ref; ref != "" { - name := getParameterNameFromNewRef(ref) - if val, ok := components.Schemas[name]; ok { - headerType = val.Value.Type - } - } else { - headerType = header.Value.Schema.Value.Type - } - - headers[name] = &openapi2.Header{ - ExtensionProps: header.Value.ExtensionProps, - Description: header.Value.Description, - Type: headerType, - } - + ref := openapi3.ParameterRef{Ref: header.Ref, Value: &header.Value.Parameter} + parameter, err := FromV3Parameter(&ref, components) + if err != nil { + return nil, err } + parameter.In = "" + parameter.Name = "" + headers[name] = &openapi2.Header{Parameter: *parameter} } - - return headers + return headers, nil } func FromV3SecurityScheme(doc3 *openapi3.T, ref *openapi3.SecuritySchemeRef) (*openapi2.SecurityScheme, error) { diff --git a/openapi2conv/openapi2_conv_test.go b/openapi2conv/openapi2_conv_test.go index 582525563..24ead5610 100644 --- a/openapi2conv/openapi2_conv_test.go +++ b/openapi2conv/openapi2_conv_test.go @@ -184,7 +184,8 @@ const exampleV2 = ` "headers": { "ETag": { "description": "The ETag (or entity tag) HTTP response header is an identifier for a specific version of a resource.", - "type": "string" + "type": "string", + "maxLength": 64 } } }, @@ -555,7 +556,8 @@ const exampleV3 = ` "ETag": { "description": "The ETag (or entity tag) HTTP response header is an identifier for a specific version of a resource.", "schema": { - "type": "string" + "type": "string", + "maxLength": 64 } } }