Default `Content-Type` not applied to complex object parts in `multipart/form-data`
Q&A
- OS: macOS
- Browser: Firefox
- Version: 122
- Method of installation: swagger-ui-dist from unpkg
- Swagger-UI version: 5.11.2
- Swagger/OpenAPI version: OpenAPI 3.0.3
Content & configuration
Example Swagger/OpenAPI definition:
openapi: 3.0.3
servers:
- url: http://127.0.0.1:8080
paths:
/profile:
post:
requestBody:
content:
multipart/form-data:
schema:
required:
- address
- id
- profileImage
type: object
properties:
id:
type: string
address:
type: object
properties:
street:
type: string
city:
type: string
profileImage:
type: string
format: binary
responses:
"200":
description: OK
Swagger-UI configuration options:
SwaggerUIBundle({
url: 'http://127.0.0.1:8080/api-docs.yaml',
dom_id: '#swagger-ui',
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
layout: "StandaloneLayout",
})
Describe the bug you're encountering
According to the OpenAPI specification and the docs page, the default Content-Type for complex values (objects) in a multipart/form-data request should be application/json.
However, in the provided example, the address property, which is an object, does not have application/json as its Content-Type in the generated request and curl command.
Currently, it's possible to manually set encoding.address.contentType in the definition as application/json to generate the expected curl command (thanks to issue #5356 was fixed).
However, based on the OpenAPI specification, I believe type=application/json should automatically be applied even if encoding is not explicitly included in the definition.
To reproduce...
Steps to reproduce the behavior:
- Fill the blanks for the /profile request
- Click on 'Execute'
- Generated curl command and payload are:
curl -X 'POST' \
'http://127.0.0.1:8080/profile' \
-H 'accept: */*' \
-H 'Content-Type: multipart/form-data' \
-F 'id=string' \
-F 'address={
"street": "string",
"city": "string"
}' \
-F '[email protected];type=text/plain'
-----------------------------306494087715324971512255078872
Content-Disposition: form-data; name="id"
string
-----------------------------306494087715324971512255078872
Content-Disposition: form-data; name="address"
{
"street": "string",
"city": "string"
}
-----------------------------306494087715324971512255078872
Content-Disposition: form-data; name="profileImage"; filename="zerobyte.txt"
Content-Type: text/plain
-----------------------------306494087715324971512255078872--
Expected behavior
curl -X 'POST' \
'http://127.0.0.1:8080/profile' \
-H 'accept: */*' \
-H 'Content-Type: multipart/form-data' \
-F 'id=string' \
-F 'address={
"street": "string",
"city": "string"
-}' \
+};type=application/json' \
-F '[email protected];type=text/plain'
-----------------------------306494087715324971512255078872
Content-Disposition: form-data; name="id"
string
-----------------------------306494087715324971512255078872
Content-Disposition: form-data; name="address"
+Content-Type: application/json
{
"street": "string",
"city": "string"
}
-----------------------------306494087715324971512255078872
Content-Disposition: form-data; name="profileImage"; filename="zerobyte.txt"
Content-Type: text/plain
-----------------------------306494087715324971512255078872--
Additional context or thoughts
- I believe specifying
Content-Type: text/plainfor theidproperty is unnecessary, as it is the default value formultipart/form-data. - This can be swagger-js issue.
EDIT: this is part (maybe duplicate) of #6462
Also bumped into this issue with a mixed multipart/form-data payload containing both files and a JSON options object. It seems that adding the encoding[fieldName].contentType fixes the CURL call, however it also causes Swagger to send a filename: "blob" in the Content-Disposition header.
OK CURL command:
curl -X 'POST' \
'http://localhost:3000/pdf/generate/' \
-H 'accept: */*' \
-H 'Content-Type: multipart/form-data' \
-F 'options={
"world": "string"
};type=application/json'
SwaggerUI request payload
------WebKitFormBoundarynwJpnsbiqaJv4Ljy
Content-Disposition: form-data; name="options"; filename="blob"
Content-Type: application/json
{
"world": "string"
}
------WebKitFormBoundarynwJpnsbiqaJv4Ljy--
Notice the filename="blob" appended to the Content-Disposition header.
Expected
------WebKitFormBoundarynwJpnsbiqaJv4Ljy
Content-Disposition: form-data; name="options";
Content-Type: application/json
{
"world": "string"
}
------WebKitFormBoundarynwJpnsbiqaJv4Ljy--
This causes subsequent multipart parsing to think of options as a file rather than an object.
I think we should at least have a coherent Curl command and Execute action. There may be multiple issues at play, setting Content-Type should probably not trigger an automatic filename although it was referenced as mandatory, and we shouldn't need to set up Content-Type for complex objects in the first place.
I will try to narrow down what is happening with the fetch request :)