Skip to content

Commit c335d5e

Browse files
Consumes Request Bodies
1 parent fc3f90d commit c335d5e

File tree

6 files changed

+159
-64
lines changed

6 files changed

+159
-64
lines changed

openapi2/openapi2.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ type Swagger struct {
2121
Info openapi3.Info `json:"info"`
2222
ExternalDocs *openapi3.ExternalDocs `json:"externalDocs,omitempty"`
2323
Schemes []string `json:"schemes,omitempty"`
24+
Consumes []string `json:"consumes,omitempty"`
2425
Host string `json:"host,omitempty"`
2526
BasePath string `json:"basePath,omitempty"`
2627
Paths map[string]*PathItem `json:"paths,omitempty"`

openapi2conv/issue187_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ paths:
155155
get:
156156
requestBody:
157157
content:
158-
application/json:
158+
'*/*':
159159
schema:
160160
$ref: '#/components/schemas/TestRef'
161161
responses:

openapi2conv/openapi2_conv.go

Lines changed: 100 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"errors"
77
"fmt"
88
"net/url"
9+
"sort"
910
"strings"
1011

1112
"github.com/getkin/kin-openapi/openapi2"
@@ -46,7 +47,7 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
4647
result.Components.Parameters = make(map[string]*openapi3.ParameterRef)
4748
result.Components.RequestBodies = make(map[string]*openapi3.RequestBodyRef)
4849
for k, parameter := range parameters {
49-
v3Parameter, v3RequestBody, v3SchemaMap, err := ToV3Parameter(&result.Components, parameter)
50+
v3Parameter, v3RequestBody, v3SchemaMap, err := ToV3Parameter(&result.Components, parameter, swagger.Consumes)
5051
switch {
5152
case err != nil:
5253
return nil, err
@@ -65,7 +66,7 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
6566
if paths := swagger.Paths; len(paths) != 0 {
6667
resultPaths := make(map[string]*openapi3.PathItem, len(paths))
6768
for path, pathItem := range paths {
68-
r, err := ToV3PathItem(swagger, &result.Components, pathItem)
69+
r, err := ToV3PathItem(swagger, &result.Components, pathItem, swagger.Consumes)
6970
if err != nil {
7071
return nil, err
7172
}
@@ -111,20 +112,20 @@ func ToV3Swagger(swagger *openapi2.Swagger) (*openapi3.Swagger, error) {
111112
return result, nil
112113
}
113114

114-
func ToV3PathItem(swagger *openapi2.Swagger, components *openapi3.Components, pathItem *openapi2.PathItem) (*openapi3.PathItem, error) {
115+
func ToV3PathItem(swagger *openapi2.Swagger, components *openapi3.Components, pathItem *openapi2.PathItem, consumes []string) (*openapi3.PathItem, error) {
115116
stripNonCustomExtensions(pathItem.Extensions)
116117
result := &openapi3.PathItem{
117118
ExtensionProps: pathItem.ExtensionProps,
118119
}
119120
for method, operation := range pathItem.Operations() {
120-
resultOperation, err := ToV3Operation(swagger, components, pathItem, operation)
121+
resultOperation, err := ToV3Operation(swagger, components, pathItem, operation, consumes)
121122
if err != nil {
122123
return nil, err
123124
}
124125
result.SetOperation(method, resultOperation)
125126
}
126127
for _, parameter := range pathItem.Parameters {
127-
v3Parameter, v3RequestBody, v3Schema, err := ToV3Parameter(components, parameter)
128+
v3Parameter, v3RequestBody, v3Schema, err := ToV3Parameter(components, parameter, consumes)
128129
switch {
129130
case err != nil:
130131
return nil, err
@@ -139,7 +140,7 @@ func ToV3PathItem(swagger *openapi2.Swagger, components *openapi3.Components, pa
139140
return result, nil
140141
}
141142

142-
func ToV3Operation(swagger *openapi2.Swagger, components *openapi3.Components, pathItem *openapi2.PathItem, operation *openapi2.Operation) (*openapi3.Operation, error) {
143+
func ToV3Operation(swagger *openapi2.Swagger, components *openapi3.Components, pathItem *openapi2.PathItem, operation *openapi2.Operation, consumes []string) (*openapi3.Operation, error) {
143144
if operation == nil {
144145
return nil, nil
145146
}
@@ -156,10 +157,14 @@ func ToV3Operation(swagger *openapi2.Swagger, components *openapi3.Components, p
156157
result.Security = &resultSecurity
157158
}
158159

160+
if len(operation.Consumes) > 0 {
161+
consumes = operation.Consumes
162+
}
163+
159164
var reqBodies []*openapi3.RequestBodyRef
160165
formDataSchemas := make(map[string]*openapi3.SchemaRef)
161166
for _, parameter := range operation.Parameters {
162-
v3Parameter, v3RequestBody, v3SchemaMap, err := ToV3Parameter(components, parameter)
167+
v3Parameter, v3RequestBody, v3SchemaMap, err := ToV3Parameter(components, parameter, consumes)
163168
switch {
164169
case err != nil:
165170
return nil, err
@@ -174,7 +179,7 @@ func ToV3Operation(swagger *openapi2.Swagger, components *openapi3.Components, p
174179
}
175180
}
176181
var err error
177-
if result.RequestBody, err = onlyOneReqBodyParam(reqBodies, formDataSchemas, components); err != nil {
182+
if result.RequestBody, err = onlyOneReqBodyParam(reqBodies, formDataSchemas, components, consumes); err != nil {
178183
return nil, err
179184
}
180185

@@ -199,7 +204,7 @@ func getParameterNameFromOldRef(ref string) string {
199204
return pathSections[0]
200205
}
201206

202-
func ToV3Parameter(components *openapi3.Components, parameter *openapi2.Parameter) (*openapi3.ParameterRef, *openapi3.RequestBodyRef, map[string]*openapi3.SchemaRef, error) {
207+
func ToV3Parameter(components *openapi3.Components, parameter *openapi2.Parameter, consumes []string) (*openapi3.ParameterRef, *openapi3.RequestBodyRef, map[string]*openapi3.SchemaRef, error) {
203208
if ref := parameter.Ref; ref != "" {
204209
if strings.HasPrefix(ref, "#/parameters/") {
205210
name := getParameterNameFromOldRef(ref)
@@ -233,7 +238,7 @@ func ToV3Parameter(components *openapi3.Components, parameter *openapi2.Paramete
233238

234239
if schemaRef := parameter.Schema; schemaRef != nil {
235240
// Assuming JSON
236-
result.WithJSONSchemaRef(ToV3SchemaRef(schemaRef))
241+
result.WithSchemaRef(ToV3SchemaRef(schemaRef), consumes)
237242
}
238243
return nil, &openapi3.RequestBodyRef{Value: result}, nil, nil
239244

@@ -314,7 +319,7 @@ func ToV3Parameter(components *openapi3.Components, parameter *openapi2.Paramete
314319
}
315320
}
316321

317-
func formDataBody(bodies map[string]*openapi3.SchemaRef, reqs map[string]bool) *openapi3.RequestBodyRef {
322+
func formDataBody(bodies map[string]*openapi3.SchemaRef, reqs map[string]bool, consumes []string) *openapi3.RequestBodyRef {
318323
if len(bodies) != len(reqs) {
319324
panic(`request bodies and them being required must match`)
320325
}
@@ -333,7 +338,7 @@ func formDataBody(bodies map[string]*openapi3.SchemaRef, reqs map[string]bool) *
333338
Required: requireds,
334339
}
335340
return &openapi3.RequestBodyRef{
336-
Value: openapi3.NewRequestBody().WithFormDataSchema(schema),
341+
Value: openapi3.NewRequestBody().WithSchema(schema, consumes),
337342
}
338343
}
339344

@@ -344,7 +349,7 @@ func getParameterNameFromNewRef(ref string) string {
344349
return pathSections[0]
345350
}
346351

347-
func onlyOneReqBodyParam(bodies []*openapi3.RequestBodyRef, formDataSchemas map[string]*openapi3.SchemaRef, components *openapi3.Components) (*openapi3.RequestBodyRef, error) {
352+
func onlyOneReqBodyParam(bodies []*openapi3.RequestBodyRef, formDataSchemas map[string]*openapi3.SchemaRef, components *openapi3.Components, consumes []string) (*openapi3.RequestBodyRef, error) {
348353
if len(bodies) > 1 {
349354
return nil, errors.New("multiple body parameters cannot exist for the same operation")
350355
}
@@ -386,7 +391,7 @@ func onlyOneReqBodyParam(bodies []*openapi3.RequestBodyRef, formDataSchemas map[
386391
}
387392
}
388393

389-
return formDataBody(formDataParams, formDataReqs), nil
394+
return formDataBody(formDataParams, formDataReqs, consumes), nil
390395
}
391396

392397
return nil, nil
@@ -601,25 +606,23 @@ func FromV3Swagger(swagger *openapi3.Swagger) (*openapi2.Swagger, error) {
601606
}
602607
}
603608

604-
for name, requestBody := range swagger.Components.RequestBodies {
605-
parameters := FromV3RequestBodyFormData(requestBody)
606-
for _, param := range parameters {
607-
result.Parameters[param.Name] = param
609+
for name, requestBodyRef := range swagger.Components.RequestBodies {
610+
bodyOrRefParameters, formDataParameters, consumes, err := FromV3RequestBodies(name, requestBodyRef, &swagger.Components)
611+
if err != nil {
612+
return nil, err
608613
}
609-
610-
if len(parameters) == 0 {
611-
paramName := name
612-
if requestBody.Value != nil {
613-
if originalName, ok := requestBody.Value.Extensions["x-originalParamName"]; ok {
614-
json.Unmarshal(originalName.(json.RawMessage), &paramName)
615-
}
614+
if len(*formDataParameters) != 0 {
615+
for _, param := range *formDataParameters {
616+
result.Parameters[param.Name] = param
616617
}
617-
618-
r, err := FromV3RequestBody(swagger, paramName, requestBody)
619-
if err != nil {
620-
return nil, err
618+
} else if len(*bodyOrRefParameters) != 0 {
619+
for _, param := range *bodyOrRefParameters {
620+
result.Parameters[name] = param
621621
}
622-
result.Parameters[name] = r
622+
}
623+
624+
if len(consumes) != 0 {
625+
result.Consumes = consumesToArray(consumes)
623626
}
624627
}
625628

@@ -638,6 +641,49 @@ func FromV3Swagger(swagger *openapi3.Swagger) (*openapi2.Swagger, error) {
638641
return result, nil
639642
}
640643

644+
func consumesToArray(consumes map[string]bool) []string {
645+
var consumesArr []string
646+
for key, _ := range consumes {
647+
consumesArr = append(consumesArr, key)
648+
}
649+
sort.Strings(consumesArr)
650+
return consumesArr
651+
}
652+
653+
func FromV3RequestBodies(name string, requestBodyRef *openapi3.RequestBodyRef, components *openapi3.Components) (*openapi2.Parameters, *openapi2.Parameters, map[string]bool, error) {
654+
formParameters := openapi2.Parameters{}
655+
bodyOrRefParameters := openapi2.Parameters{}
656+
if ref := requestBodyRef.Ref; ref != "" {
657+
bodyOrRefParameters = append(bodyOrRefParameters, &openapi2.Parameter{Ref: FromV3Ref(ref)})
658+
return &bodyOrRefParameters, &formParameters, nil, nil
659+
}
660+
661+
//Only select one formData or request body for an individual requesstBody as swagger 2 does not support multiples
662+
consumes := make(map[string]bool)
663+
if requestBodyRef.Value != nil {
664+
for contentType, mediaType := range requestBodyRef.Value.Content {
665+
//add each type to the consumes array
666+
consumes[contentType] = true
667+
formParams := FromV3RequestBodyFormData(mediaType)
668+
if len(formParams) != 0 {
669+
formParameters = formParams
670+
} else {
671+
paramName := name
672+
if originalName, ok := requestBodyRef.Value.Extensions["x-originalParamName"]; ok {
673+
json.Unmarshal(originalName.(json.RawMessage), &paramName)
674+
}
675+
676+
r, err := FromV3RequestBody(paramName, requestBodyRef, mediaType, components)
677+
if err != nil {
678+
return &bodyOrRefParameters, &formParameters, consumes, err
679+
}
680+
bodyOrRefParameters = append(bodyOrRefParameters, r)
681+
}
682+
}
683+
}
684+
return &bodyOrRefParameters, &formParameters, consumes, nil
685+
}
686+
641687
func FromV3Schemas(schemas map[string]*openapi3.SchemaRef, components *openapi3.Components) (map[string]*openapi3.SchemaRef, map[string]*openapi2.Parameter) {
642688
v2Defs := make(map[string]*openapi3.SchemaRef)
643689
v2Params := make(map[string]*openapi2.Parameter)
@@ -770,11 +816,7 @@ nameSearch:
770816
return ""
771817
}
772818

773-
func FromV3RequestBodyFormData(requestBodyRef *openapi3.RequestBodyRef) openapi2.Parameters {
774-
mediaType := requestBodyRef.Value.GetMediaType("multipart/form-data")
775-
if mediaType == nil {
776-
return nil
777-
}
819+
func FromV3RequestBodyFormData(mediaType *openapi3.MediaType) openapi2.Parameters {
778820
parameters := openapi2.Parameters{}
779821
for propName, schemaRef := range mediaType.Schema.Value.Properties {
780822
if ref := schemaRef.Ref; ref != "" {
@@ -848,27 +890,30 @@ func FromV3Operation(swagger *openapi3.Swagger, operation *openapi3.Operation) (
848890
result.Parameters = append(result.Parameters, r)
849891
}
850892
if v := operation.RequestBody; v != nil {
851-
parameters := FromV3RequestBodyFormData(operation.RequestBody)
852-
if len(parameters) > 0 {
853-
result.Parameters = append(result.Parameters, parameters...)
854-
} else {
855-
// Find parameter name that we can use for the body
856-
name := findNameForRequestBody(operation)
857-
if name == "" {
858-
return nil, errors.New("could not find a name for request body")
859-
}
860-
r, err := FromV3RequestBody(swagger, name, v)
861-
if err != nil {
862-
return nil, err
893+
// Find parameter name that we can use for the body
894+
name := findNameForRequestBody(operation)
895+
if name == "" {
896+
return nil, errors.New("could not find a name for request body")
897+
}
898+
899+
bodyOrRefParameters, formDataParameters, consumes, err := FromV3RequestBodies(name, v, &swagger.Components)
900+
if err != nil {
901+
return nil, err
902+
}
903+
if len(*formDataParameters) != 0 {
904+
result.Parameters = append(result.Parameters, *formDataParameters...)
905+
} else if len(*bodyOrRefParameters) != 0 {
906+
//add a single request body
907+
for i, param := range *bodyOrRefParameters {
908+
if i == 0 {
909+
result.Parameters = append(result.Parameters, param)
910+
}
863911
}
864-
result.Parameters = append(result.Parameters, r)
912+
865913
}
866-
}
867914

868-
for _, param := range result.Parameters {
869-
if param.Type == "file" {
870-
result.Consumes = append(result.Consumes, "multipart/form-data")
871-
break
915+
if len(consumes) != 0 {
916+
result.Consumes = consumesToArray(consumes)
872917
}
873918
}
874919

@@ -882,10 +927,7 @@ func FromV3Operation(swagger *openapi3.Swagger, operation *openapi3.Operation) (
882927
return result, nil
883928
}
884929

885-
func FromV3RequestBody(swagger *openapi3.Swagger, name string, requestBodyRef *openapi3.RequestBodyRef) (*openapi2.Parameter, error) {
886-
if ref := requestBodyRef.Ref; ref != "" {
887-
return &openapi2.Parameter{Ref: FromV3Ref(ref)}, nil
888-
}
930+
func FromV3RequestBody(name string, requestBodyRef *openapi3.RequestBodyRef, mediaType *openapi3.MediaType, components *openapi3.Components) (*openapi2.Parameter, error) {
889931
requestBody := requestBodyRef.Value
890932

891933
stripNonCustomExtensions(requestBody.Extensions)
@@ -897,10 +939,8 @@ func FromV3RequestBody(swagger *openapi3.Swagger, name string, requestBodyRef *o
897939
ExtensionProps: requestBody.ExtensionProps,
898940
}
899941

900-
// Assuming JSON
901-
mediaType := requestBody.GetMediaType("application/json")
902942
if mediaType != nil {
903-
result.Schema, _ = FromV3SchemaRef(mediaType.Schema, &swagger.Components)
943+
result.Schema, _ = FromV3SchemaRef(mediaType.Schema, components)
904944
}
905945
return result, nil
906946
}

openapi2conv/openapi2_conv_test.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ const exampleV2 = `
8888
"version": "0.1",
8989
"x-info": "info extension"
9090
},
91+
"consumes": [
92+
"application/json",
93+
"application/xml"
94+
],
9195
"parameters": {
9296
"banana": {
9397
"in": "path",
@@ -224,15 +228,19 @@ const exampleV2 = `
224228
}
225229
},
226230
"patch": {
231+
"consumes": [
232+
"application/json",
233+
"application/xml"
234+
],
227235
"description": "example patch",
228236
"parameters": [
229237
{
230238
"in": "body",
231-
"name": "body",
239+
"name": "patch_body",
232240
"schema": {
233241
"allOf": [{"$ref": "#/definitions/Item"}]
234242
},
235-
"x-originalParamName":"body",
243+
"x-originalParamName":"patch_body",
236244
"x-requestBody": "requestbody extension 1"
237245
}
238246
],
@@ -345,6 +353,11 @@ const exampleV3 = `
345353
"schema": {
346354
"type": "string"
347355
}
356+
},
357+
"application/xml": {
358+
"schema": {
359+
"type": "string"
360+
}
348361
}
349362
},
350363
"required": true,
@@ -539,9 +552,14 @@ const exampleV3 = `
539552
"schema": {
540553
"allOf": [{"$ref": "#/components/schemas/Item"}]
541554
}
555+
},
556+
"application/xml": {
557+
"schema": {
558+
"allOf": [{"$ref": "#/components/schemas/Item"}]
559+
}
542560
}
543561
},
544-
"x-originalParamName":"body",
562+
"x-originalParamName":"patch_body",
545563
"x-requestBody": "requestbody extension 1"
546564
},
547565
"responses": {

0 commit comments

Comments
 (0)