question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot generate description for a file upload API

See original GitHub issue

My 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:open
  • Created 4 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

7reactions
RicoSutercommented, May 5, 2020

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.

5reactions
FreBoncommented, Apr 27, 2020

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…

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can not upload file when using a swagger generated ...
I was able to workaround the problem by modifying the generated server code to change the name "file" in @RequestPart("file") to the name ......
Read more >
REST API for Documents - Upload File
The REST API for Documents enables you to interact with folders and files stored in Oracle Content Management Cloud and to create sites...
Read more >
File Upload
Swagger 2.0 supports file uploads sent with Content-Type: multipart/form-data . That is, your API server must consume multipart/form-data for this operation:.
Read more >
Upload file data | Google Drive
The Google Drive API lets you upload file data when you create or update a File . For information about how to create...
Read more >
Spring Boot File Download and Upload REST API Examples
How to implement REST APIs for File upload and download with Spring Boot. Full Java code examples.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found