flask-smorest response and return type different

Issue

I am learning/working on a Rest Api suing flask-smorest and adding the schema using marshmallow.

Below is the code that I am confused with and have a question.

Schemas.py

class ChildAddressDetailsSchema(Schema):
    class Meta:
        unknown = EXCLUDE

    address_id = fields.String(required=True)
    address_type = fields.String(required=True)
    is_primary = fields.Boolean(required=True)


class ChildAddressDetailsSchemaList(Schema):
    class Meta:
        unknown = EXCLUDE

    person_list = fields.List(fields.Nested(ChildAddressDetailsSchema))

Endpoint Implementation

@address_blueprint.response(status_code=200, schema=ChildAddressDetailsSchema)
@address_blueprint.get('/child/address/<string:person_id>/list')
def get_child_address(person_id):
    person_address_list = PersonAddressModel.query.filter_by(person_id=person_id).all()
    person_address_dict = [{'address_id': person_address.address_id,
                            'address_type': person_address.address_type,
                            'is_primary': person_address.is_primary} for person_address in person_address_list]

    return person_address_dict

The part where I have doubt is even though the schema defined in response of blueprint is
ChildAddressDetailsSchema which is not a list , still I get a valid response.Below is the screenshot of the Insomnia from where I am testing the api.

enter image description here

I was expecting an empty response or a error since the return of the get function get_child_address is a list of dictionary which is not as per the schema. Could someone please help me figuring out on to how to fix the issue and return type is strictly informed. Is this something that needs to be coded or does marshmallow handles this.

Solution

It’s because you called Blueprint.response() before Blueprint.get(). So do like this.

@address_blueprint.get('/child/address/<string:person_id>/list')
@address_blueprint.response(status_code=200, schema=ChildAddressDetailsSchema)
def get_child_address(person_id):
    ...

A Python decorator returns a new function that calls the original function. So the order of decorators matters in general. In this case, the implementation of the ResponseMixin.response() of Flask Smorest does not work correctly if the Blueprint.route()(which is equivalent to the Scaffold.get()) is not called before.

You can see that on this and this. If the ResponseMixin.response() is called before the Blueprint.route(), the closure wrapper(created at the decorator() inside the ResponseMixin.response()) will be ignored, because the add_url_rule() will be called with the original endpoint function not the wrapper, at the decorator() inside the Blueprint.route().

Answered By – relent95

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published