pythonflaskmarshmallowwebargsflask-smorest

How to use a list of arguments with flask_smorest/marshmallow


I am trying to insert a collection of objects in a flask api. We use marshmallow for deserializing. My endpoint looks like this:

        @blp.arguments(SomeSchemas, location='json', as_kwargs=True)
        @blp.response(200, SomeSchemas)
        def post(self, some_schemas: SomeSchemas) -> dict:

The schema is a simple schema like this:

class SomeSchemas(ma.Schema):
    schemas = ma.fields.List(ma.fields.Nested(SomeSchema))

class SomeSchema(ma.Schema):
    a = ma.fields.String()
    b = ma.fields.Integer()

When i post to the endpoint, I do get a list of the correct data, but it comes in the form of dicts, instead of being correctly translated into the object.

I have also tried explicitly using a list of objects (List[SomeSchema], SomeSchema(many=True), etc.) but I can not seem to figure it out.

I assume this is a very common use case (providing a list of arguments) and that I am missing an obvious solution, but I can't seem to find any reference as to how to do this correctly. To be clear, I am looking for the correct way to call the endpoint with a list (or some other collection type, it does not matter) and have said list be correctly deserialized and with the correct object type.


Solution

  • Disclaimer: flask-smorest maintainer speaking.

    I don't think the issue is related to the fact that the input is a list.

    IIUC, your problem is that you're gettings dicts, rather than objects, injected in the view function. This is the default marshmallow behaviour. It can be overridden in marshmallow by using a post_load hook to actually instantiate the object.

    I generally don't do that. In practice I find it better to instantiate objects in the view function. For instance, in a PUT resource, I prefer to instantiate the existing item from DB then update it with new data. In this case it is better to have the new data as dict than object.

    There may not be a single truth, here, it could be a matter of opinion, but while the idea of having the object instantiated in the decorator and passed to the view is appealing, it might be a bit of an abusive shortcut.


    I realize this answer is of the "no idea but you shouldn't do it anyway" type. Just saying maybe you shouldn't struggle to achieve this.

    This said, I'd be surprised if it worked with non-list / non-nested inputs and I'd wonder why it doesn't work specifically in this case.