Should I use Singular or Plural name convention for REST resources?

Viewed 274869

I'm new to REST and I've observed that in some RESTful services they use different resource URI for update/get/delete and Create. Such as

  • Create - using /resources with POST method (observe plural) at some places using /resource (singular)
  • Update - using /resource/123 with PUT method
  • Get - Using /resource/123 with GET method

I'm little bit confused about this URI naming convention. What should we use plural or singular for resource creation? What should be the criteria while deciding that?

25 Answers

See Google's API Design Guide: Resource Names for another take on naming resources.

The guide requires collections to be named with plurals.

|--------------------------+---------------+-------------------+---------------+--------------|
| API Service Name         | Collection ID | Resource ID       | Collection ID | Resource ID  |
|--------------------------+---------------+-------------------+---------------+--------------|
| //mail.googleapis.com    | /users        | /name@example.com | /settings     | /customFrom  |
| //storage.googleapis.com | /buckets      | /bucket-id        | /objects      | /object-id   |
|--------------------------+---------------+-------------------+---------------+--------------|

It's worthwhile reading if you're thinking about this subject.

An id in a route should be viewed the same as an index to a list, and naming should proceed accordingly.

numbers = [1, 2, 3]

numbers            GET /numbers
numbers[1]         GET /numbers/1
numbers.push(4)    POST /numbers
numbers[1] = 23    PUT /numbers/1

But some resources don't use ids in their routes because there's either only one, or a user never has access to more than one, so those aren't lists:

GET /dashboard
DELETE /session
POST /session
GET /users/{:id}/profile
PUT /users/{:id}/profile

The Most Important Thing

Any time you are using plurals in interfaces and code, ask yourself, how does your convention handle words like these:

  • /pants, /eye-glasses - are those the singular or the plural path?

  • /radii - do you know off the top of your head if the singular path for that is /radius or /radix?

  • /index - do you know off the top of your head if plural path for that is /indexes or /indeces or /indices?

Conventions should ideally scale without irregularity. English plurals do not do this, because

  1. they have exceptions like one of something being called by the plural form, and
  2. there is no trivial algorithm to get the plural of a word from the singular, get the singular from the plural, or tell if an unknown noun is singular or plural.

This has downsides. The most prominent ones off the top of my head:

  1. The nouns whose singular and plural forms are the same will force your code to handle the case where the "plural" endpoint and the "singular" endpoint have the same path anyway.
  2. Your users/developers have to be proficient with English enough to know the correct singulars and plurals for nouns. In an increasingly internationalized world, this can cause non-negligible frustration and overhead.
  3. It singlehandedly turns "I know /foo/{{id}}, what's the path to get all foo?" into a natural language problem instead of a "just drop the last path part" problem.

Meanwhile, some human languages don't even have different singular and plural forms for nouns. They manage just fine. So can your API.

I don't like to see the {id} part of the URLs overlap with sub-resources, as an id could theoretically be anything and there would be ambiguity. It is mixing different concepts (identifiers and sub-resource names).

Similar issues are often seen in enum constants or folder structures, where different concepts are mixed (for example, when you have folders Tigers, Lions and Cheetahs, and then also a folder called Animals at the same level -- this makes no sense as one is a subset of the other).

In general I think the last named part of an endpoint should be singular if it deals with a single entity at a time, and plural if it deals with a list of entities.

So endpoints that deal with a single user:

GET  /user             -> Not allowed, 400
GET  /user/{id}        -> Returns user with given id
POST /user             -> Creates a new user
PUT  /user/{id}        -> Updates user with given id
DELETE /user/{id}      -> Deletes user with given id

Then there is separate resource for doing queries on users, which generally return a list:

GET /users             -> Lists all users, optionally filtered by way of parameters
GET /users/new?since=x -> Gets all users that are new since a specific time
GET /users/top?max=x   -> Gets top X active users

And here some examples of a sub-resource that deals with a specific user:

GET /user/{id}/friends -> Returns a list of friends of given user

Make a friend (many to many link):

PUT /user/{id}/friend/{id}     -> Befriends two users
DELETE /user/{id}/friend/{id}  -> Unfriends two users
GET /user/{id}/friend/{id}     -> Gets status of friendship between two users

There is never any ambiguity, and the plural or singular naming of the resource is a hint to the user what they can expect (list or object). There are no restrictions on ids, theoretically making it possible to have a user with the id new without overlapping with a (potential future) sub-resource name.

Use Singular and take advantage of the English convention seen in e.g. "Business Directory".

Lots of things read this way: "Book Case", "Dog Pack", "Art Gallery", "Film Festival", "Car Lot", etc.

This conveniently matches the url path left to right. Item type on the left. Set type on the right.

Does GET /users really ever fetch a set of users? Not usually. It fetches a set of stubs containing a key and perhaps a username. So it's not really /users anyway. It's an index of users, or a "user index" if you will. Why not call it that? It's a /user/index. Since we've named the set type, we can have multiple types showing different projections of a user without resorting to query parameters e.g. user/phone-list or /user/mailing-list.

And what about User 300? It's still /user/300.

GET /user/index
GET /user/{id}

POST /user
PUT /user/{id}

DELETE /user/{id}

In closing, HTTP can only ever have a single response to a single request. A path is always referring to a singular something.

Here's Roy Fielding dissertation of "Architectural Styles and the Design of Network-based Software Architectures", and this quote might be of your interest:

A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.

Being a resource, a mapping to a set of entities, doesn't seem logical to me, to use /product/ as resource for accessing set of products, rather than /products/ itself. And if you need a particular product, then you access /products/1/.

As a further reference, this source has some words and examples on resource naming convention:

Great discussion points on this matter. Naming conventions or rather not establishing local standards has been in my experience the root cause of many long nights on-call, headaches, risky refactoring, dodgy deployments, code review debates, etc, etc, etc. Particularly when its decided that things need to change because insufficient consideration was given at the start.

An actual issue tracked discussion on this:

https://github.com/kubernetes/kubernetes/issues/18622

It is interesting to see the divide on this.

My two cents (with a light seasoning of headache experience) is that when you consider common entities like a user, post, order, document etc. you should always address them as the actual entity since that is what a data model is based on. Grammar and model entities shouldn't really be mixed up here and this will cause other points of confusion. However, is everything always black and white? Rarely so indeed. Context really matters.

When you wish to get a collection of users in a system, for example:

GET /user -> Collection of entity User

GET /user/1 -> Resource of entity User:1

It is both valid to say I want a collection of entity user and to say I want the users collection.

GET /users -> Collection of entity User

GET /users/1 -> Resource of entity User:1

From this you are saying, from the collection of users, give me user /1.

But if you break down what a collection of users is... Is it a collection of entities where each entity is a User entity.

You would not say entity is Users since a single database table is typically an individual record for a User. However, we are talking about a RESTful service here not a database ERM.

But this is only for a User with clear noun distinction and is an easy one to grasp. Things get very complex when you have multiple conflicting approaches in one system though.

Truthfully, either approach makes sense most of the time bar a few cases where English is just spaghetti. It appears to be a language that forces a number of decisions on us!

The simple fact of the matter is that no matter what you decide, be consistent and logical in your intent.

Just appears to me that mixing here and there is a bad approach! This quietly introduces some semantic ambiguity which can be totally avoided.

Seemingly singular preference:

https://www.haproxy.com/blog/using-haproxy-as-an-api-gateway-part-1/

Similar vein of discussion here:

https://softwareengineering.stackexchange.com/questions/245202/what-is-the-argument-for-singular-nouns-in-restful-api-resource-naming

The overarching constant here is that it does indeed appear to be down to some degree of team/company cultural preferences with many pros and cons for both ways as per details found in the larger company guidelines. Google isn't necessarily right, just because it is Google! This holds true for any guidelines.

Avoid burying your head in the sand too much and loosely establishing your entire system of understanding on anecdotal examples and opinions.

Is it imperative that you establish solid reasoning for everything. If it scales for you, or your team and/our your customers and makes sense for new and seasoned devs (if you are in a team environment), nice one.

How about:

/resource/ (not /resource)

/resource/ means it's a folder contains something called "resource", it's a "resouce" folder.

And also I think the naming convention of database tables is the same, for example, a table called 'user' is a "user table", it contains something called "user".

Related