Skip to content

Commit

Permalink
conversion: conversion for file upload from v2 to v3 and vice versa (#…
Browse files Browse the repository at this point in the history
…233)

This change enables converting spec for file upload with POST from v2 to v3 and vice versa
according to https://swagger.io/docs/specification/2-0/file-upload/ specification.
Added support for `multipart/form-data`.
Added `in: formData` case for file upload.
Updated unit tests related sections.
  • Loading branch information
gitforbit authored Jul 15, 2020
1 parent 4581141 commit 100b968
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 15 deletions.
118 changes: 105 additions & 13 deletions openapi2conv/openapi2_conv.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,51 @@ func ToV3PathItem(swagger *openapi2.Swagger, pathItem *openapi2.PathItem) (*open
return result, nil
}

func ToV3RequestBodyFormData(parameters []*openapi2.Parameter) *openapi3.RequestBodyRef {
if len(parameters) == 0 || parameters[0].In != "formData" {
return nil
}
schema := &openapi3.Schema{
Type: "object",
Properties: make(map[string]*openapi3.SchemaRef, len(parameters)),
}
for _, parameter := range parameters {
if parameter.In != "formData" || parameter.Name == "" {
continue
}
format := parameter.Format
typ := parameter.Type
if parameter.Type == "file" {
format = "binary"
typ = "string"
}
pschema := &openapi3.Schema{
Description: parameter.Description,
Type: typ,
ExtensionProps: parameter.ExtensionProps,
Format: format,
Enum: parameter.Enum,
Min: parameter.Minimum,
Max: parameter.Maximum,
ExclusiveMin: parameter.ExclusiveMin,
ExclusiveMax: parameter.ExclusiveMax,
MinLength: parameter.MinLength,
MaxLength: parameter.MaxLength,
Default: parameter.Default,
Items: parameter.Items,
MinItems: parameter.MinItems,
MaxItems: parameter.MaxItems,
}
schemaRef := openapi3.SchemaRef{
Value: pschema,
}
schema.Properties[parameter.Name] = &schemaRef
}
return &openapi3.RequestBodyRef{
Value: openapi3.NewRequestBody().WithFormDataSchema(schema),
}
}

func ToV3Operation(swagger *openapi2.Swagger, pathItem *openapi2.PathItem, operation *openapi2.Operation) (*openapi3.Operation, error) {
if operation == nil {
return nil, nil
Expand All @@ -137,15 +182,21 @@ func ToV3Operation(swagger *openapi2.Swagger, pathItem *openapi2.PathItem, opera
resultSecurity := ToV3SecurityRequirements(*v)
result.Security = &resultSecurity
}
for _, parameter := range operation.Parameters {
v3Parameter, v3RequestBody, err := ToV3Parameter(parameter)
if err != nil {
return nil, err
}
if v3RequestBody != nil {
result.RequestBody = v3RequestBody
} else if v3Parameter != nil {
result.Parameters = append(result.Parameters, v3Parameter)

requestBodyRef := ToV3RequestBodyFormData(operation.Parameters)
if requestBodyRef != nil {
result.RequestBody = requestBodyRef
} else {
for _, parameter := range operation.Parameters {
v3Parameter, v3RequestBody, err := ToV3Parameter(parameter)
if err != nil {
return nil, err
}
if v3RequestBody != nil {
result.RequestBody = v3RequestBody
} else if v3Parameter != nil {
result.Parameters = append(result.Parameters, v3Parameter)
}
}
}
if responses := operation.Responses; responses != nil {
Expand Down Expand Up @@ -515,6 +566,42 @@ nameSearch:
return ""
}

func FromV3RequestBodyFormData(requestBodyRef *openapi3.RequestBodyRef) openapi2.Parameters {
mediaType := requestBodyRef.Value.GetMediaType("multipart/form-data")
if mediaType == nil {
return nil
}
parameters := openapi2.Parameters{}
for prop, schemaRef := range mediaType.Schema.Value.Properties {
val := schemaRef.Value
typ := val.Type
if val.Format == "binary" {
typ = "file"
}
parameter := &openapi2.Parameter{
Name: prop,
Description: val.Description,
Type: typ,
In: "formData",
ExtensionProps: val.ExtensionProps,
Enum: val.Enum,
ExclusiveMin: val.ExclusiveMin,
ExclusiveMax: val.ExclusiveMax,
MinLength: val.MinLength,
MaxLength: val.MaxLength,
Default: val.Default,
Items: val.Items,
MinItems: val.MinItems,
MaxItems: val.MaxItems,
Maximum: val.Max,
Minimum: val.Min,
Pattern: val.Pattern,
}
parameters = append(parameters, parameter)
}
return parameters
}

func FromV3Operation(swagger *openapi3.Swagger, operation *openapi3.Operation) (*openapi2.Operation, error) {
if operation == nil {
return nil, nil
Expand All @@ -539,11 +626,16 @@ func FromV3Operation(swagger *openapi3.Swagger, operation *openapi3.Operation) (
result.Parameters = append(result.Parameters, r)
}
if v := operation.RequestBody; v != nil {
r, err := FromV3RequestBody(swagger, operation, v)
if err != nil {
return nil, err
parameters := FromV3RequestBodyFormData(operation.RequestBody)
if len(parameters) > 0 {
result.Parameters = append(result.Parameters, parameters...)
} else {
r, err := FromV3RequestBody(swagger, operation, v)
if err != nil {
return nil, err
}
result.Parameters = append(result.Parameters, r)
}
result.Parameters = append(result.Parameters, r)
}
if responses := operation.Responses; responses != nil {
resultResponses, err := FromV3Responses(responses)
Expand Down
40 changes: 38 additions & 2 deletions openapi2conv/openapi2_conv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,22 @@ const exampleV2 = `
},
"post": {
"description": "example post",
"responses": {}
"responses": {},
"parameters": [
{
"in": "formData",
"name": "fileUpload",
"type": "file",
"description": "param description",
"x-mimetype": "text/plain"
},
{
"in": "formData",
"name":"note",
"type": "integer",
"description": "Description of file contents"
}
]
},
"put": {
"description": "example put",
Expand Down Expand Up @@ -424,7 +439,28 @@ const exampleV3 = `
},
"post": {
"description": "example post",
"responses": {}
"responses": {},
"requestBody": {
"content": {
"multipart/form-data": {
"schema": {
"properties": {
"fileUpload": {
"description": "param description",
"format": "binary",
"type": "string",
"x-mimetype": "text/plain"
},
"note":{
"type": "integer",
"description": "Description of file contents"
}
},
"type": "object"
}
}
}
}
},
"put": {
"description": "example put",
Expand Down
12 changes: 12 additions & 0 deletions openapi3/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ func NewContentWithJSONSchemaRef(schema *SchemaRef) Content {
}
}

func NewContentWithFormDataSchema(schema *Schema) Content {
return Content{
"multipart/form-data": NewMediaType().WithSchema(schema),
}
}

func NewContentWithFormDataSchemaRef(schema *SchemaRef) Content {
return Content{
"multipart/form-data": NewMediaType().WithSchemaRef(schema),
}
}

func (content Content) Get(mime string) *MediaType {
// If the mime is empty then short-circuit to the wildcard.
// We do this here so that we catch only the specific case of
Expand Down
10 changes: 10 additions & 0 deletions openapi3/request_body.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ func (requestBody *RequestBody) WithJSONSchema(value *Schema) *RequestBody {
return requestBody
}

func (requestBody *RequestBody) WithFormDataSchemaRef(value *SchemaRef) *RequestBody {
requestBody.Content = NewContentWithFormDataSchemaRef(value)
return requestBody
}

func (requestBody *RequestBody) WithFormDataSchema(value *Schema) *RequestBody {
requestBody.Content = NewContentWithFormDataSchema(value)
return requestBody
}

func (requestBody *RequestBody) GetMediaType(mediaType string) *MediaType {
m := requestBody.Content
if m == nil {
Expand Down

0 comments on commit 100b968

Please sign in to comment.