Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: [FromForm] does not generate a property in schema but makes itself the schema #3094

Closed
warappa opened this issue Oct 2, 2024 · 1 comment · Fixed by #3095
Closed
Labels
Milestone

Comments

@warappa
Copy link

warappa commented Oct 2, 2024

Describe the bug

I have a Minimal API. In previous versions of this library I had to patch the generated schema to have tags in the schema next to file (-> properties of schema object).

I heard, in the newer versions of this library [FromForm] is better supported, so I tried that.
Unfortunately, one of my endpoints relying on [FromForm] yields a schema that is incorrect.

I have a Minimal API with the following action:

app.MapPost(
    "{tool}/{scenario}/{fileName}",
    async (
        string tool,
        string scenario,
        string fileName,
        [FromForm(Name = "tags")] string tags,
        IFormFile file,
        HttpRequest request) =>
    {
        return Results.Ok();
    })
.WithName("Upload")
.DisableAntiforgery()
.WithOpenApi();

Note

A simpler version without file also shows this behavior.

Expected behavior

It should generate:

{
    "operationId": "Upload",
    "parameters": [
        {
            "name": "tool",
            "in": "path",
            "required": true,
            "schema": {
                "type": "string"
            }
        },
        {
            "name": "scenario",
            "in": "query",
            "required": true,
            "schema": {
                "type": "string"
            }
        },
        {
            "name": "fileName",
            "in": "path",
            "required": true,
            "schema": {
                "type": "string"
            }
        }
    ],
    "requestBody": {
        "content": {
            "multipart/form-data": {
                "schema": {
                    "required": [
                        "file"
                    ],
                    "type": "object",
                    "properties": {
                        "file": {
                            "type": "string",
                            "format": "binary"
                        },
                        "tags": {
                            "type": "string"
                        }
                    }
                },
                "encoding": {
                    "tags": {
                        "style": "form"
                    },
                    "file": {
                        "style": "form"
                    }
                }
            }
        },
        "required": true
    },
    "responses": {
        "200": {
            "description": "OK"
        }
    }
}

Note

Please note the file and tags properties in the schema. This way I can send a tags string alongside the binary file payload.

Note

tags in encoding is just a guess on my side.

Actual behavior

It generates:

"post": {
    "operationId": "Upload",
    "parameters": [
        {
            "name": "tool",
            "in": "path",
            "required": true,
            "schema": {
                "type": "string"
            }
        },
        {
            "name": "scenario",
            "in": "query",
            "required": true,
            "schema": {
                "type": "string"
            }
        },
        {
            "name": "fileName",
            "in": "path",
            "required": true,
            "schema": {
                "type": "string"
            }
        }
    ],
    "requestBody": {
        "content": {
            "multipart/form-data": {
                "schema": {
                    "allOf": [
                        {
                            "type": "string"
                        },
                        {
                            "required": [
                                "file"
                            ],
                            "type": "object",
                            "properties": {
                                "file": {
                                    "type": "string",
                                    "format": "binary"
                                }
                            }
                        }
                    ]
                },
                "encoding": {
                    "tags": {
                        "style": "form"
                    },
                    "file": {
                        "style": "form"
                    }
                }
            }
        },
        "required": true
    },
    "responses": {
        "200": {
            "description": "OK"
        }
    }
}

This schema would mean, that the body is a mix of a string (tags) and something with a property file that is a binary file (⚠ note the allOf). That is incorrect.

Note

A simpler version without file also shows this behavior (but with skipping allOf).

Note

As to be expected, Swagger UI is also not able to display a tags input anywhere

Steps to reproduce

  1. Create new minimal API project with .NET 8 from template
  2. Configure to use swagger gen
  3. Add endpoint like in example
  4. Update Swagger libraries
  5. Browse to the generated swagger.json and inspect generated OpenAPI schema

Exception(s) (if any)

No response

Swashbuckle.AspNetCore version

6.8.1

.NET Version

net8.0

Anything else?

No response

@warappa warappa added the bug label Oct 2, 2024
@martincostello martincostello added the help-wanted A change up for grabs for contributions from the community label Oct 2, 2024
@jgarciadelanoceda
Copy link
Contributor

jgarciadelanoceda commented Oct 2, 2024

I am working on it. It's a fix over the PRs: #2979, #2972 and #2963.
The problem that the previous version had is that if there is no schema it has to create the properties and so on.
The AllOf is OK (Because the implementation of Microsoft.AspNetCore.OpenApi does just the same (if there is more than one element then it creates an AllOf node.

This is how it's going to get rendered:

"post": {
	"operationId": "Upload",
	"parameters": [
		{
			"name": "tool",
			"in": "path",
			"required": true,
			"schema": {
				"type": "string"
			}
		},
		{
			"name": "scenario",
			"in": "query",
			"required": true,
			"schema": {
				"type": "string"
			}
		},
		{
			"name": "fileName",
			"in": "path",
			"required": true,
			"schema": {
				"type": "string"
			}
		}
	],
	"requestBody": {
		"content": {
			"multipart/form-data": {
				"schema": {
					"allOf": [
						{
							"type": "object",
							"properties": {
								"tags": {
									"type": "string"
								}
							}
						},
						{
							"required": [
								"file"
							],
							"type": "object",
							"properties": {
								"file": {
									"type": "string",
									"format": "binary"
								}
							}
						}
					]
				},
				"encoding": {
					"tags": {
						"style": "form"
					},
					"file": {
						"style": "form"
					}
				}
			}
		},
		"required": true
	},
	"responses": {
		"200": {
			"description": "OK"
		}
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
3 participants