domaindrivendev / Swashbuckle.AspNetCore

Swagger tools for documenting API's built on ASP.NET Core
MIT License
5.21k stars 1.3k forks source link

[Bug]: IFormFile & FromForm swagger UI generates bad request #3029

Open sf-declanomalley opened 1 month ago

sf-declanomalley commented 1 month ago

Describe the bug

in version 6.5 of Swashbuckle.AspNetCore the swashbuckle UI generates a request like the following

------WebKitFormBoundarytyM4fpDlZaqBRSR9
Content-Disposition: form-data; name="file"; filename="PMS-Project Core-250624-120110.pdf"
Content-Type: application/pdf

------WebKitFormBoundarytyM4fpDlZaqBRSR9
Content-Disposition: form-data; name="payload"

{
  "references": [
    {
      "key": "tes",
      "value": "aw"
    }
  ]
}
------WebKitFormBoundarytyM4fpDlZaqBRSR9--

however upgrading to 6.6.1 or higher (have upgraded to 6.7.0) the UI generates a request like the following:

------WebKitFormBoundary5vvdQ6zjNU7A7ABN
Content-Disposition: form-data; name="file"; filename="PMS-Project Core-250624-120110.pdf"
Content-Type: application/pdf

------WebKitFormBoundary5vvdQ6zjNU7A7ABN
Content-Disposition: form-data; name="payload"; filename="blob"
Content-Type: application/json

{"references":[{"key":"tes","value":"aa"}]}
------WebKitFormBoundary5vvdQ6zjNU7A7ABN--

as you can see the payload formdata has been tagged as a file. the only difference between the swagger definition between the 2 versions (6.5 and 6.7) is that the response codes changes from "Ok" to "Success" but the requests are very different.

the swagger definition looks like the following.

{
  "openapi": "3.0.1",
  "info": {
    "title": "Documents",
    "version": "1.0"
  },
  "paths": {
    "/File/{container}/{folder}": {
      "post": {
        "tags": [
          "Upload"
        ],
        "operationId": "/Upload",
        "parameters": [
          {
            "name": "container",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "folder",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file",
                  "payload"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    },
                    "format": "binary"
                  },
                  "payload": {
                    "$ref": "#/components/schemas/NewDocument"
                  }
                }
              },
              "encoding": {
                "payload": {
                  "contentType": "application/json"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "code": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "message": {
            "type": "string",
            "nullable": true
          },
          "details": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "NewDocument": {
        "type": "object",
        "properties": {
          "references": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Reference"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Reference": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    }
  }
}

Expected behavior

request to be the same from the swashbuckle UI for the same swagger definition and generate a form where not specified as binary.

Actual behavior

is sending form data as a file.

Steps to reproduce

pass the swagger definition defined in "Describe the bug" to swashbuckle UI in version 6.5. look at the generated request from developer tools and compare to the request in version 6.7 or swashbuckle.

Exception(s) (if any)

No response

Swashbuckle.AspNetCore version

6.7.0

.NET Version

net8.0

Anything else?

No response

martincostello commented 4 weeks ago

If the generated OpenAPI document is essentially the same between the two versions, then this must be an upstream issue with swagger-ui.

You should report the issue in the swagger-api/swagger-ui repo, and we will pick up any fix in a future version.