How to describe dynamic form data using OpenAPI (Swagger)? - swagger

I'm trying to create an OpenAPI definition for this multipart/form-data request:
curl -X POST \
http://localhost:1234/api/v1/Submit \
-H 'cache-control: no-cache' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-H 'sessionkey: kjYgfORsZ0GeiCls0FcR7w==' \
-F item1=abc \
-F item2=def
-F item3=ghi
...
My API definition is like this:
post:
consumes:
- multipart/form-data
produces:
- application/json
parameters:
- in: formData
name: item1
type: string
- in: formData
name: item2
type: string
It works fine with fixed fields in formData.
However, my form data will be dynamic, and I need to be able to send arbitrary keys and values.
I tried changing form parameters to use an array and additionalProperties, but it does not produce the desired result:
- in: formData
schema:
additionalProperties:
type: object
...
- in: formData
type: array
items:
type: string
Is it possible to define dynamic formData with different keys and values?

Dynamic form data can be defined using OpenAPI 3.0 but not OpenAPI 2.0 (Swagger 2.0). OpenAPI 2.0 only supports fixed key names in form data.
In OpenAPI 3.0, you can describe dynamic form data using a schema with additionalProperties:
openapi: 3.0.2
...
servers:
- url: 'http://localhost:1234/api/v1'
paths:
/Submit:
post:
requestBody:
required: true
content:
multipart/form-data:
schema:
# Object properties correspond to form fields
type: object
additionalProperties:
type: string
responses:
'200':
description: OK
When testing the request in Swagger UI, enter the fields names and values in the JSON format:
{
"field1": "value1",
"field2": "value2",
"field3": "value3"
}
Swagger UI will send these values as individual form fields:

Related

Array of files in Swagger

How to define a list of files in Swagger?
Here is what I did but it doesn't work.
OpenAPI 2.0
In OpenAPI 2.0 (swagger: '2.0'), you have to define each file as a separate parameter. This means you can only describe requests that send a fixed/limited number of files. There is no way to define an unbound array of files.
paths:
/something:
post:
consumes:
- multipart/form-data
parameters:
- in: formData
name: file1
type: file
- in: formData
name: file2
type: file
- ...
OpenAPI 3.0
Arrays of files are supported in OpenAPI 3.0. The request can be defined as follows:
openapi: 3.0.0
paths:
/something:
post:
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
# "reports" will be used as the name of each file part/field
# in the multipart request
reports:
type: array
items:
type: string
format: binary
OpenAPI 3.1
OAS 3.1 also supports file arrays, but the syntax is slightly different from 3.0. Specifically, file arrays use items: {} instead of binary string items.
openapi: 3.1.0
paths:
/something:
post:
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
# "reports" will be used as the name of each file part/field
# in the multipart request
reports:
type: array
items: {}

swagger-ui - open api 3, multipart/form-data array problem

I'm uising swagger-ui with OpenApi 3.0.2 spec.
I set a requestBody with multipart/form-data content.
Everithing works fine when I execute the request from swagger-ui but...
If I add a parameter of type array, it will be transformed in curl call in this way:
-F "tags=my,tag"
I need the array to be exploded
-F 'tags[]=my' \
-F 'tags[]=tag'
I look at the documentation and find some style and explode properties, but they only works on parameters attribute, not on requestBody (?).
In my route file:
post:
tags:
- media-image
summary: Create a media image
requestBody:
description: A JSON object containing media image information
required: true
content:
multipart/form-data:
schema:
allOf:
- $ref: '../schemas/media-image-fillable.yaml'
- required:
- title
- back_office_title
- alt
- file
The media-image-fillable.yaml
type: object
allOf:
- $ref: './media-image-base.yaml'
- properties:
file:
type: string
format: binary
tags:
type: array
items:
type: string
and the media-image-base.yaml
type: object
properties:
title:
type: string
back_office_title:
type: string
description:
type: string
alt:
type: string
Ok, I found the solution.
I only had to rename tags property in tags[], now it works.

open api 3 posting an array of files

I am using swagger hub to create this API; but it doesn't support multi files in the UI so I am unsure if I am doing this right
My goal is to have the following
item:{Json describe the item}
images[] = images for item posted as an array
titles[] = Parallel array to images that has the title for image
alt_texts[] = Parallel array to images that has the alt text for image
This has to be multipart since it is files; but am unsure if I setup the structure correctly.
Swagger/Open API Code
post:
summary: Add a new item to the store
description: ''
operationId: addItem
requestBody:
content:
multipart/form-data:
schema:
$ref: '#/components/schemas/NewItemWithImage'
description: Item object that needs to be added to the store
required: true
NewItemWithImage:
type: object
properties:
item:
$ref: '#/components/schemas/NewItem'
images[]:
type: array
items:
type: string
format: binary
titles[]:
type: array
items:
type: string
alt_texts[]:
type: array
items:
type: string
variation_ids[]:
type: array
items:
type: string
required:
- item
According to File Upload section in OpenAPI 3 specification:
File Upload
Files use a type: string schema with format: binary or format: base64,
depending on how the file contents will be encoded.
Multiple File Upload
Use the
multipart media type to define uploading an arbitrary number of files
(an array of files):
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
filename:
type: array
items:
type: string
format: binary
You current definition corresponds to the specification precisely:
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/NewItemWithImageUrl'
multipart/form-data:
schema:
$ref: '#/components/schemas/NewItemWithImage'
NewItemWithImage:
type: object
properties:
item:
$ref: '#/components/schemas/NewItem'
images[]:
type: array
items:
type: string
format: binary
titles[]:
type: array
items:
type: string
...
The code for swagger-ui is failing as of today in curlify.js
if (v instanceof win.File) {
curlified.push( `"${k}=#${v.name}${v.type ? `;type=${v.type}` : ""}"` )
} else {
curlified.push( `"${k}=${v}"` )
}
curlify.js is not taking the array into account and is sending:
curl -X POST "http://localhost:9122/upload-all" -H "accept: */*" -H "Content-Type: multipart/form-data" -F "my-attachment=[object File],[object File]"
and not something like:
curl -X POST "https://foo/v1/api/upload/" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "myfile=#bla;type=application/zip" -F "myfile=#foo;type=application/zip"

Swagger-ui problems trying to use a object parameter containing a array

Seem to almost have it...
Trying to have swagger send an anonymous hash of parameters in the request body.
I have an anonymous hash containing one key named list that contains an array.
Trying to send this parameter (text/json):
{
list : [ 'string1', 'string2' ]
}
Swagger is building the right curl statement but is not sending the parameters via the UI.
Swagger builds this (works from command line):
/usr/bin/curl -H 'Content-Type: text/json' -X GET -d '{ "list" : [ "text:/export/home/ihome/perl5/our_modules/check_parse_lib_rest/t/data/hosts:/export/home/ihome/perl5/our_modules/check_parse_lib_rest/t/data/hosts", "text:/export/home/ihome/perl5/our_modules/check_parse_lib_rest/t/data/hosts:/export/home/ihome/perl5/our_modules/check_parse_lib_rest/t/data/hosts.1" ] }' 'https://localhost.localdomain:9086/library/check_diff_batch'
But Swagger-ui shows no model example and sends no parameters in the request body.
In the editor I see it the list shows as undefined.
Schema
⇄
Comparison {
list:
ComparisonList undefined *
}
Definition -
paths:
/check_diff_batch:
get:
summary: Compare a list of file comparrison objects using diff.
description: |
FIXME: Takes an array of colon delimited comparrison objects.
Required parameter Comparrison object format = type:file1:file2
**RC** will return false if there are differences or a failure.
**FAULT_MSG** will return No Faults or a failure message.
parameters:
- $ref: "#/parameters/ComparrisonList"
responses:
200:
description: Successful response
examples:
text/json:
...
parameters:
ComparrisonList:
name: list
in: body
description: List of comparrison objects
schema:
$ref: "#/definitions/Comparisons"
definitions:
Comparisons:
required:
- list
properties:
list:
$ref: "#/definitions/ComparisonList"
ComparisonList:
additionalProperties:
type: string
additionalProperties is used to define associative arrays / hashmaps, not regular arrays. A regular string array is defined as:
definitions:
ComparisonList:
type: array
items:
type: string
You should also use a post operation and not get, since request body in GET does not have defined semantics as per RFC 7231 section 4.3.1.

Write swagger doc that consumes multiple content types e.g. application/json AND application/x-www-form-urlencoded (w/o duplication)

I'm looking for an elegant way to define an api that can consume JSON data as well as form data. The following snippet works, but it's not elegant and requires all kind of ugly code in the backend. Is there a better way to define this?
What works right now:
paths:
/pets:
post:
consumes:
- application/x-www-form-urlencoded
- application/json
parameters:
- name: nameFormData
in: formData
description: Updated name of the pet
required: false
type: string
- name: nameJSON
in: body
description: Updated name of the pet
required: false
type: string
Basic idea of how I'd like it to work:
paths:
/pets:
post:
consumes:
- application/x-www-form-urlencoded
- application/json
parameters:
- name: name
in:
- formData
- body
description: Updated name of the pet
required: true
type: string
But this doesn't work because the in value must be a string, not an array.
Any good ideas?
OpenAPI 2.0
In OpenAPI 2.0, there's no way to describe that. Form and body parameters are mutually exclusive, so an operation can have either form data OR JSON body but not both. A possible workaround is to have two separate endpoints - one for form data and another one for JSON - if that is acceptable in your scenario.
OpenAPI 3.0
Your scenario can be described using OpenAPI 3.0. The requestBody.content.<media-type> keyword is used to define various media types accepted by the operation, such as application/json and application/x-www-form-urlencoded, and their schemas. Media types can have the same schema or different schemas.
openapi: 3.0.0
...
paths:
/pets:
post:
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/Pet'
responses:
'200':
description: OK
components:
schemas:
Pet:
type: object
properties:
name:
type: string
description: Updated name of the pet
required:
- name
Further info:
OAS3: Describing Request Body
https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#support-for-x-www-form-urlencoded-request-bodies
https://blog.readme.io/an-example-filled-guide-to-swagger-3-2/#requestformat

Resources