miLibris / flask-rest-jsonapi

Flask extension to build REST APIs around JSONAPI 1.0 specification.
http://flask-rest-jsonapi.readthedocs.io
MIT License
598 stars 153 forks source link

Automatically filter related resources by their owner #176

Closed multimeric closed 3 years ago

multimeric commented 4 years ago

In the basic example we use api.route(ComputerList, 'computer_list', '/computers', '/persons/<int:id>/computers'), which adds a route for fetching all computers (/computers), or all computers related to a person (/persons/<int:id>/computers).

However, if you create a simple ResourceList like this, requests to /persons/<int:id>/computers will return all computers, not just those associated with a certain person:

class ComputerList(ResourceList):
    schema = ComputerSchema
    data_layer = {
        'session': db.session,
        'model': Computer,
    }

In the example, this is solved using a custom filter:

class ComputerList(ResourceList):
    def query(self, view_kwargs):
        query_ = self.session.query(Computer)
        if view_kwargs.get('id') is not None:
            try:
                self.session.query(Person).filter_by(id=view_kwargs['id']).one()
            except NoResultFound:
                raise ObjectNotFound({'parameter': 'id'}, "Person: {} not found".format(view_kwargs['id']))
            else:
                query_ = query_.join(Person).filter(Person.id == view_kwargs['id'])
        return query_

    def before_create_object(self, data, view_kwargs):
        if view_kwargs.get('id') is not None:
            person = self.session.query(Person).filter_by(id=view_kwargs['id']).one()
            data['person_id'] = person.id

However, there's no reason we can't automate this filtering, in the same way that we do for ResourceRelationship fields (although these are different). It's incredibly common to want `/persons/1/computers to return only the computers from person 1.