restrestful-url

RESTful API Multiple Query Strings over multiple Resources for Filtering


Let´s assume there is an entity companies and an entity nations. A company can belong to many nations and a nation can have multiple companies. So there is a intermediate table memberships with different roles for the companies e.g. a company is a manufacturer in a nation and another company is for example a supplier in a nation. A nation can have multiple status like is_active etc.

Now we want to fetch all nations from a specific company where the role is manufacturer and the state of the nation is is_active = false.

How could a RESTful API endpoint look for this use case? Is it allowed to filter over multiple resources? Some ideas:

GET /companies/{id}/nations?role=manufacturer&is_active=false

GET /memberships/{id}/nations?role=manufacturer&is_active=false

UPDATE
Maybe my question was not clear enough. The query string parameters make a lookup in two different tables/entities. The role is inside the memberships entity and the is_active is inside the nations entity. I thought that filtering is allowed only on the requested resource. Maybe I could split up the question in two use cases.

  1. Is it "better" to go with the intermediate resource in the URI?
  2. Can we filter a resource with query string parameters over multiple tables/entities?

Solution

  • REST doesn't care what spelling you use for your identifiers. Any data encoded into the URI is done at the server's discretion and for its own use.

    Which basically means that as long as your URI conforms to RFC 3986, you are doing the right thing. That means:

    Hierarchical data belongs in the path - that allows generic clients to parse relative references the correct way. Non hierarchical data belongs in the query.

    Is it allowed to filter over multiple resources?

    Other way around - the identifier matches up with a single resource that may load/filter state from multiple rows of data.

    GET /companies/{id}/nations?role=manufacturer&is_active=false
    GET /companies/{id}/nations?role=manufacturer&is_active=true
    

    Those are two different resources; the fact that they happen to be backed by the same parameterized query is an implementation detail.

    The query string parameters make a lookup in two different tables/entities.

    That's an implementation detail. As far as the API consumer is concerned, you could just be pulling a prepared document out of a key value store.

    That's part of the point, here -- the API should be stable even if the underlying implementation needs to change. Tightly coupling your integration interface to your current data schema makes backwards compatible changes more difficult.

    I thought that filtering is allowed only on the requested resource.

    No. As far as REST is concerned, the entire URI is a single identifier. Client's use that URI to access and manipulate the resource. There's absolutely no REST constraint on what the implementation of the resource looks like behind the interface. It could be a document store, a single table, many tables, a 3rd party service, some combination of all of these....

    The server side framework that you are using to provide the current representation may care -- some identifiers fit better with your routing strategies than others, the framework may restrict you to a convention where the data needs to be stored in a single place. But those are all just implementation details. REST does not care.

    Can we filter a resource with query string parameters over multiple tables/entities?

    "Filter a resource" isn't quite the right spelling to use, because it confuses your integration resources (the things that REST cares about) with your data model.

    Can the representation of a single resource be created from data stored in multiple tables? Of course. Can the resource be restricted to data from those tables that satisfies some filtering specification? Of course. Is there any restriction on which filters can be applied to which tables? No.

    Jim Webber:

    URI do NOT map onto domain objects - that violates encapsulation.... You should expect to have many many more resources in your integration domain than you do business objects in your business domain.