Question

I have a question related to REST URL design. I found some relevant posts here Different RESTful representations of the same resource and here RESTful url to GET resource by different fields but the responses are not quite clear on what the best practices are and why. Here's an example.

I have REST URLs for representing "users" resource. I can GET a user with an id or with an email address but the URL representation remains the same for both. Going through a lot of blogs and books I see that people have been doing this in many different ways. For example

read this practice in a book and somewhere on stackoverflow (I can't seem to find the link again)

GET /users/id={id}
GET /users/email={email}

read this practice on a lot of blogs

GET /users/{id}
GET /users/email/{email}

Query params are normally used for filtering the results of the resources represented by the URL, but I have seen this practice being used as well

GET /users?id={id}
GET /users?email={email}

My question is, out of all these practices, which one would make the most sense to developers consuming the APIs and why? I believe there are no rules set in stone when it comes to REST URL designs and naming conventions, but I just wanted to know which route I should take to help developers better understand the APIs.

Was it helpful?

Solution

In my experience, GET /users/{id} GET /users/email/{email} is the most common approach. I would also expect the methods to return a 404 Not Found if a user doesn't exist with the provided id or email. I wouldn't be surprised to see GET /users/id/{id}, either (though in my opinion, it is redundant).

Comments on the other approaches

  1. GET /users/id={id} GET /users/email={email}
    • I don't think I've seen this, and if I did see it, it would be very confusing. It's almost like it's trying to imitate query parameters with path parameters.
  2. GET /users?id={id} GET /users?email={email}
    • I think you hit the nail on the head when you mentioned using query parameters for filtering.
    • Would it ever make sense to call this resource with both an id and an email (e.g. GET /users?id={id}&email={email})? If not, I wouldn't use a single resource method like this.
    • I would expect this method for retrieving a list of users with optional query parameters for filtering, but I would not expect id, email or any unique identifier to be among the parameters. For example: GET /users?status=BANNED might return a list of banned users.

Check out this answer from a related question.

OTHER TIPS

Looking at this pragmatically, you've got a collection of users:

/users   # this returns many

Each user has a dedicated resource location:

/users/{id}    # this returns one

You've also got a number of ways to search for users:

/users?email={email}
/users?name=*bob*

Since these are all query parameters to /users, they should all return lists.. even if it's a list of 1.

I wrote a blog post on pragmatic RESTful API design here that talks about this, among other things, here: http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api

About the user resources

- Singleton

on the path /users/[user_id] you can expect several things to happen, for example:

  • you should get a singleton resource representing the user resource with its identifier [user_id] or
  • a not found 404 response if no user with id [user_id] exists or
  • a forbidden 401 if you are not allowed to access the requested user resource.

Each singleton is uniquely identified by its path and identifier and you use these to find the resource. It is not possible to use several paths for the singleton.

- Collection

on the path /users you will always get a collection of user resources returned.

You can query the path /users with query parameters (GET Parameters). This will return a collection with users that meet the requested criteria. The collection that is returned should contain the user resources, all with their identifying resource path in the response. Search parameters could be any field present in the resources of the collection; firstName, lastName, id

So for example:

/users?id=1
/users?firstName=John
/users?lastName=Doe

or even a combination of the above:

/users?firstName=John&lastName=Doe

The collection response will always be an array. The array can be empty (no matches), contain one item (conclusive) or several items (inconclusive).

About the email

The email can be either a resource or a property/field of the user resource.

- Email as property of user:

If the field is a property of user the user response would look something like this:

{ 
  id: 1,
  firstName: 'John'
  lastName: 'Doe'
  email: 'john.doe@example.com'
  ...
}

This means there is no special endpoint for emails, but you can now find a user by its email by sending following request: /users?email=john.doe@example.com. Which (assuming emails are unique to users) would return a collection with one user item that matches the email.

- Email as a resource:

But if emails from users are also resources. Then you could make an API where /users/[user_id]/emails returns a collection of email addresses for user with id user_id. /users/[user_id]/emails/[email_id] returns the email of user with user_id and ['email_id']. What you use as an identifier is up to you, but I would stick to an integer. You can delete an email from the user by sending a DELETE request to the path that identifies the email you want to delete. So for example DELETE on /users/[user_id]/emails/[email_id] will delete the email with email_id that is owned by user with user_id. Most likely only that user is allowed to perform this delete operation. Other users will get a 401 response.

If a user can have only one email address you can stick to /users/[user_id]/email This returns a singleton resource. The user can update his email address by PUTting the email address at that url.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top