REST API filter / sort with flask (and webargs, marshmallow, sqlalchemy)

1.5k views Asked by At

I'm working on my first flask-classful / sqlalchemy / marshmallow REST API. I have a Delivery table in my database with a status enum:

  • new
  • requested
  • dispatched
  • arrived
  • closed

As expected, GET /deliveries/ returns a list of deliveries. Here's a current code extract from the view:

deliveries_schema = DeliverySchema(many=True)  # a marshmallow-sqlalchemy ModelSchema

class Deliveries(FlaskView):
    @use_kwargs(deliveries_schema.fields)
    def index(self, **kwargs):
        deliveries = Delivery.query.filter_by(**kwargs)
        return deliveries_schema.jsonify(incidents)

Yes, I pass webargs parameters straight to filter_by. However let's say for a given screen in the client, I need to see only deliveries with status new or requested. It clearly makes sense to implement some sort of filter grammar, as I'm going to want to perform similar operations on all kinds

Unfortunately the following GETs fail:

  • /deliveries/?status=new&status=requested returns only deliveries with status=new - in fact it always chooses the first of the two.
  • As a fairly random experiment /deliveries/?status=new,requested results in marshmallow-sqlalchemy returning 422 Unprocessable Entity, which is understandable as new,requested is not an option in the status enum. I'm not sure if this is a feature or a bug.

As an aside, I can successfully pass two different filter parameters e.g. /deliveries/?status=requested&user_id=123 works as expected.

Anyway, the same goes for sorting and pagination. At present I have no idea how to handle them in my API. Current issues as I see them:

  • I'll need to add parameters that don't map to DeliverySchema. This seems to indicate that there will be an impact on the schema code.
  • I can't just blindly throw all the parameters to filter_by, because some of the parameters won't be filters. But for this first use case I'd be happy to just be able to filter based on statuses new and requested. Sorting and pagination can come later.
  • The grammar logic needs to be implemented somewhere.

I don't even know where in the stack this should be handled, let alone how to implement a solution. Surely this is a pretty common use case, any pointers appreciated.

0

There are 0 answers