Search code examples
restapi-design

How to properly access children by filtering parents in a single REST API call


I'm rewriting an API to be more RESTful, but I'm struggling with a design issue. I'll explain the situation first and then my question.

SITUATION:

I have two sets resources users and items. Each user has a list of item, so the resource path would like something like this:

api/v1/users/{userId}/items

Also each user has an isPrimary property, but only one user can be primary at a time. This means that if I want to get the primary user you'd do something like this:

api/v1/users?isPrimary=true

This should return a single "primary" user.

I have client of my API that wants to get the items of the primary user, but can't make two API calls (one to get the primary user and the second to get the items of the user, using the userId). Instead the client would like to make a single API call.

QUESTION:

How should I got about designing an API that fetches the items of a single user in only one API call when all the client has is the isPrimary query parameter for the user?

MY THOUGHTS:

I think I have a some options:

Option 1) api/v1/users?isPrimary=true will return the list of items along with the user data.

I don't like this one, because I have other API clients that call api/v1/users or api/v1/users?isPrimary=true to only get and parse through user data NOT item data. A user can have thousands of items, so returning those items every time would be taxing on both the client and the service.

Option 2) api/v1/users/items?isPrimary=true

I also don't like this because it's ugly and not really RESTful since there is not {userId} in the path and isPrimary isn't a property of items.

Option 3) api/v1/users?isPrimary=true&isShowingItems=true

This is like the first one, but I use another query parameter to flag whether or not to show the items belonging to the user in the response. The problem is that the query parameter is misleading because there is no isShowingItems property associated with a user.

Any help that you all could provide will be greatly appreciated. Thanks in advance.


Solution

  • There's no real standard solution for this, and all of your solutions are in my mind valid. So my answer will be a bit subjective.

    Have you looked at HAL for your API format? HAL has a standard way to embed data from one resources into another (using _embedded) and it sounds like a pretty valid use-case for this.

    The server can decide whether to embed the items based on a number of criteria, but one cheap solution might be to just add a query parameter like ?embed=items

    Even if you don't use HAL, conceptually you could still copy this behavior similarly. Or maybe you only use _embedded. At least it's re-using an existing idea over building something new.

    Aside from that practical solution, there is nothing in un-RESTful about exposing data at multiple endpoints. So if you created a resource like:

    /v1/primary-user-with-items
    

    Then this might be ugly and inconsistent with the rest of your API, but not inherently 'not RESTful' (sorry for the double negative).