REST API DESIGN - Getting a resource through REST with different parameters but same url pattern

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.


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

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

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

  1. you should get a singleton resource representing the user resource with its identifier [user_id] or
  2. a not found 404 response if no user with id [user_id] exists or
  3. 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.

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.

Parameters could be any field present in the resources of the collection; firstName, lastName, id

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: '[email protected]'
  ...
}

This means there is no special endpoint for emails, but you can now find a user by its email by sending following request: /[email protected]. 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.