marshmallow-code / marshmallow-code/flask-smorest

Swagger submitting incorrect format for Model-based form inputs

Open
#566 4 comments 0 reactions 0 assignees View on GitHub
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:

Screenshot 2023-10-12 at 3 39 42 PM

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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.