I have the following endpoint in Flask
:
from flask import Flask
from marshmallow import EXCLUDE, Schema, fields
from webargs.flaskparser import use_kwargs
app = Flask(
__name__, static_url_path="", static_folder="static", template_folder="templates"
)
class Measure(Schema):
type = fields.Int(required=True)
value = fields.Float(required=True)
unit = fields.Int(required=True)
date = fields.Int(required=True)
class RequestSchema(Schema):
measures = fields.List(fields.Nested(Measure))
@app.route("/save", methods=["POST"])
@use_kwargs(
RequestSchema,
location="json_or_form",
unknown=EXCLUDE,
)
def save(**measures):
return {"foo": measures}, 200
With pytest
, I test the following:
import pytest
@pytest.fixture(scope="module")
def app():
test_app = AppClientPublic()
return test_app.app
def test_save(app):
measures = [
{
"type": 1,
"value": 2.2,
"unit": 3,
"date": 4,
},
{
"type": 5,
"value": 6.6,
"unit": 7,
"date": 8,
},
]
r = app.post(
"/save",
data={"measures": measures},
)
assert r.status_code == 200
I get the following error:
Error 422 Unprocessable Entity: The request was well-formed but was unable to be followed due to semantic errors. - {'messages': {'json_or_form': {'measures': {0: {'_schema': ['Invalid input type.']}, 1: {'_schema': ['Invalid input type.']}}}}, 'schema': <RequestSchema(many=False)>, 'headers': None}
However, if I validate the same dictionary directly:
d = {
"measures": [
{
"type": 1,
"value": 2.2,
"unit": 3,
"date": 4,
},
{
"type": 5,
"value": 6.6,
"unit": 7,
"date": 8,
},
]
}
req_schema = RequestSchema()
errors = req_schema.validate(d)
print(errors) # {} -> no errors
I get no validation error.
I also have absolutely no problem validating simple objects like just a depth-1 dictionary, but I am unable to validate a list of Measure
on the Flask endpoint.
What am I doing wrong?
PS:
use_kwargs
on the Flask endpoint.The problem was on the pytest
side, not the Flask
side.
I changed the post
call to use json
instead of data
:
r = app.post("/save", json={"measures": measures})
# instead of
r = app.post("/save", data={"measures": measures})