marshmallow-code / marshmallow-code/flask-smorest
Swagger submitting incorrect format for Model-based form inputs
- Dominant language
- Python
- Stars
- 717
- Forks
- 77
- Avg merge
- 7h 49m
- Merged PRs (30d)
- 3
Description
Hi, this is a bit of an edge case I'm running into, but I hope it's solvable with some configuration. It is also possible this is a bug with swagger itself, or I'm just using things in an unintended way.
# The Problem
The swagger configuration generated for my form endpoint does not submit list data in a valid way. All other usage works fine, everything passes tests, etc. It is only when trying to use swagger UI's "Try it out" does this fail.
The failure mode is that swagger submits lists of items like `my_values=a,b`, but should be submitting via the `my_values=a&my_values=b`, i.e. the way of `explode=True`, `style='form'` in OpenAPI 3.0+. As form data, my backend does not properly parse the comma-separated method.
# Reproducing
Assume the following schema and endpoint:
```python
from marshmallow import Schema, fields
# Schema
class MyFormData(Schema):
my_values = fields.List(fields.String())
# API
blueprint = Blueprint(
"forms",
"forms",
url_prefix="/forms"
)
@blueprint.route("/my-form")
class MyForm(MethodView):
@blueprint.arguments(MyFormData, location="form")
def post(self, data):
"""
Submit form
"""
print(data)
pass
```
POST-ing to this endpoint via swagger with values and the form encoding like this:
yields a curl statement like this:
```
curl -X 'POST' \
'http://localhost:8060/forms/my-form' \
-H 'accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'my_values=a,b'
```
Which we can confirm by seeing the print output that this is not parsed into two values:
```python
# in post handler
print(data)
> OrderedDict([('my_values', ['a,b'])])
```
The relevant bits of `openapi.json` looks something like:
```json
"paths": {
"/forms/my-form": {
"post": {
"requestBody": {
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"$ref": "#/components/schemas/MyFormData"
}
}
}
},
"tags": [
"forms"
]
}
},
...
"MyFormData": {
"type": "object",
"properties": {
"my_values": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
```
# Related Work
This appears at least tangentially related to https://github.com/marshmallow-code/apispec/issues/500 and the fix https://github.com/marshmallow-code/apispec/pull/778. I wasn't able to parse out if there is anything in there that I can action on though.
Thanks for taking the time to read - any thoughts on a potential workaround for fix would be appreciated.
Contributor guide
Research direction
Start at the form endpoint using blueprint.arguments(MyFormData, location="form") and inspect the generated openapi.json requestBody for application/x-www-form-urlencoded. Compare the Swagger UI request with the related apispec work; done means repeated list values are submitted separately and parsed as distinct values by the endpoint.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- flask, openapi, python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100