Cannot generate description for a file upload API
See original GitHub issueMy current problem is I’m trying to implement a simple uploading API that could work from both my client and swaggerUI but I didn’t succeed yet.
Consider following controller:
[ApiController]
[Route("[controller]/[action]")]
[Produces(MediaTypeNames.Application.Json)]
public class ConfirmController : ControllerBase
{
[HttpPost("{taskId}")]
[Consumes(MediaTypeNames.Image.Jpeg, MediaTypeNames.Application.Octet, "image/png")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task Photo(Guid taskId, [FromBody] Stream file)
{
}
}
This description generates an almost proper swagger description
"/Confirm/Photo/{taskId}": {
"post": {
"tags": [
"Confirm"
],
"operationId": "Confirm_Photo",
"parameters": [
{
"name": "taskId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "guid"
},
"x-position": 1
}
],
"requestBody": {
"x-name": "file",
"content": {
"application/json": {
"schema": {
"type": "string",
"format": "byte",
"nullable": false
}
}
},
"required": true,
"x-position": 2
},
"responses": {
"401": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageModel"
}
}
}
},
"200": {
"description": ""
},
"403": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageModel"
}
}
}
}
}
}
}
But it doesn’t work: I’m getting 415 Unsupported Media Type
when I click Execute
button in swaggerUI. As a bonus Stream
argument is considered to be an application/json
, instead of what I specified in ConsumesAttribute
.
If I change [FromBody]
to [FromForm]
attribute then I’m able to call method without getting 415
error, but swaggerUI is either unable to perform request at all (see https://github.com/swagger-api/swagger-ui/issues/5821 ) or just sends empty body instead of file.
For example this method
[HttpPost("{taskId}")]
[Consumes("multipart/form-data")]
[ProducesResponseType(StatusCodes.Status200OK)]
public async Task Photo(Guid taskId, [FromForm] IFormFile file)
{
}
Will produce following swagger.json:
{
"x-generator": "NSwag v13.2.2.0 (NJsonSchema v10.1.4.0 (Newtonsoft.Json v12.0.0.0))",
"openapi": "3.0.0",
"info": {
"title": "API",
"version": "v1"
},
"servers": [
{
"url": "http://localhost:55555"
}
],
"paths": {
"/Confirm/Photo/{taskId}": {
"post": {
"tags": [
"Confirm"
],
"operationId": "Confirm_Photo",
"parameters": [
{
"name": "taskId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"format": "guid"
},
"x-position": 1
},
{
"name": "ContentType",
"in": "formData",
"schema": {
"type": "string",
"nullable": true
},
"x-position": 2
},
{
"name": "ContentDisposition",
"in": "formData",
"schema": {
"type": "string",
"nullable": true
},
"x-position": 3
},
{
"name": "Headers",
"in": "formData",
"schema": {
"nullable": true,
"oneOf": [
{
"$ref": "#/components/schemas/IHeaderDictionary"
}
]
},
"x-position": 4
},
{
"name": "Length",
"in": "formData",
"schema": {
"type": "integer",
"format": "int64"
},
"x-position": 5
},
{
"name": "Name",
"in": "formData",
"schema": {
"type": "string",
"nullable": true
},
"x-position": 6
},
{
"name": "FileName",
"in": "formData",
"schema": {
"type": "string",
"nullable": true
},
"x-position": 7
}
],
"responses": {
"401": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageModel"
}
}
}
},
"200": {
"description": ""
},
"403": {
"description": "",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/MessageModel"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"MessageModel": {
"type": "object",
"additionalProperties": false,
"properties": {
"Message": {
"type": "string",
"nullable": true
}
}
},
"IHeaderDictionary": {
"type": "object",
"x-abstract": true,
"additionalProperties": false,
"properties": {
"Item": {
"type": "array",
"items": {
"type": "string"
}
},
"ContentLength": {
"type": "integer",
"format": "int64",
"nullable": true
}
}
}
},
"securitySchemes": {
"Bearer": {
"type": "apiKey",
"description": "Type into the textbox: Bearer {your auth token}.",
"name": "Authorization",
"in": "header"
}
}
},
"security": [
{
"Bearer": []
}
]
}
Which is invalid as you can check at https://editor.swagger.io/ :
Structural error at paths./Confirm/Photo/{taskId}.post.parameters.1.in
should be equal to one of the allowed values
allowedValues: path, query, header, cookie
Jump to line 23
Structural error at paths./Confirm/Photo/{taskId}.post.parameters.2.in
should be equal to one of the allowed values
allowedValues: path, query, header, cookie
Jump to line 29
Structural error at paths./Confirm/Photo/{taskId}.post.parameters.3.in
should be equal to one of the allowed values
allowedValues: path, query, header, cookie
Jump to line 35
Structural error at paths./Confirm/Photo/{taskId}.post.parameters.4.in
should be equal to one of the allowed values
allowedValues: path, query, header, cookie
Jump to line 42
Structural error at paths./Confirm/Photo/{taskId}.post.parameters.5.in
should be equal to one of the allowed values
allowedValues: path, query, header, cookie
Jump to line 48
Structural error at paths./Confirm/Photo/{taskId}.post.parameters.6.in
should be equal to one of the allowed values
allowedValues: path, query, header, cookie
Jump to line 54
So my question is how do I describe a regular octet/stream
and/or formdata
to make it work in all cases?
All this applies to asp netcoreapp3.1
Issue Analytics
- State:
- Created 4 years ago
- Comments:8 (3 by maintainers)
I see there is a problem and we should really try to fix this so that ppl do not need to use v2… hope to find time soon. Need to look into lots of file scenarios and add lots of tests.
Got the same issue, any updates/workarounds? the attribute that @RicoSuter mentions didn’t work 😦.
I’m using IFormFile as an in parameter and got it to work when calling the function from a client. But it doesn’t work from Swagger UI, but my real problem is that I’m using the generated swagger definition json file to update my Azure API Management instance. And that fails due to validation errors mentioned above…