REST API Design: Nested Collection vs. New Root - rest

This question is about optimal REST API design and a problem I'm facing to choose between nested resources and root level collections.
To demonstrate the concept, suppose I have collections City, Business, and Employees. A typical API may be constructed as follows. Imagine that ABC, X7N and WWW are keys, e.g. guids:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/City/ABC/Businesses/X7N (returns business X7N)
GET Api/City/ABC/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/City/ABC/Businesses/X7N/Employees/WWW (updates employee WWW)
This appears clean because it follows the original domain structure - business are in a city, and employees are at a business. Individual items are accessible via key under the collection (e.g. ../Businesses returns all businesses, while ../Businesses/X7N returns the individual business).
Here is what the API consumer needs to be able to do:
Get businesses in a city (GET Api/City/ABC/Businesses)
Get all employees at a business (GET Api/City/ABC/Businesses/X7N/Employees)
Update individual employee information (PUT Api/City/ABC/Businesses/X7N/Employees/WWW)
That second and third call, while appearing to be in the right place, use a lot of parameters that are actually unnecessary.
To get employees at a business, the only parameter needed is the key of the business (X7N).
To update an individual employee, the only parameter needed it the key of the employee (WWW)
Nothing in the backend code requires non-key information to look up the business or update the employee. So, instead, the following endpoints appear better:
GET Api/City/ABC/Businesses (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Businesses/X7N/Employees (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
As you can see, I've created a new root for businesses and employees, even though from a domain perspective they are a sub/sub-sub-collection.
Neither solution appears very clean to me.
The first example asks for unnecessary information, but is structured in a way that appears "natural" to the consumer (individual items from a collection are retrieved via lower leafs)
The second example only asks for necessary information, but isn't structured in a "natural" way - subcollections are accessible via roots
The individual employee root would not work when adding a new employee, as we need to know which business to add the employee to, which means that call would at least have to reside under the Business root, such as POST Api/Businesses/X7N7/Employees, which makes everything even more confusing.
Is there a cleaner, third way that I'm not thinking of?

I don't see how REST adds a constraint that two resources could not have the same value. The resourceType/ID is just an example of the easiest use case rather than the best way to go from a RESTful point of view.
If you read paragraph 5.2.1.1 of Roy Fielding's dissertation carefully, you will notice that Fielding makes the disctinction between a value and a resource. Now a resource should have a unique URI, that's true. But nothing prevents two resources from having the same value:
For example, the "authors' preferred version" of an academic paper is a mapping whose value changes over time, whereas a mapping to "the paper published in the proceedings of conference X" is static. These are two distinct resources, even if they both map to the same value at some point in time. The distinction is necessary so that both resources can be identified and referenced independently. A similar example from software engineering is the separate identification of a version-controlled source code file when referring to the "latest revision", "revision number 1.2.7", or "revision included with the Orange release."
So nothing prevents you from, as you say, changing the root. In your example, a Business is a value not a resource. It is perfectly RESTful to create a resource which is a list of "every business located in a city" (just like Roy's example, "revisions included with the Orange release"), while having a "business which ID is x" resource as well (like "revision number x").
For Employees, I would keep API/Businesses/X7N/Employees as the relation between a business and its employees is a composition relationship, and thus as you say, Employees can and should only be accessed through the Businesses class root. But this is not a REST requirement, and the other alternative is perfectly RESTful as well.
Note that this goes in pair with the application of the HATEAOS principle. In your API, the list of Businesses located in a city could (and perhaps should from a theoretical point of view) be just a list of links to the API/Businesses. But this would mean that the clients would have to do one round-trip to the server for each of the items in the list. This is not efficient and, to stay pragmatic, what I do is embed the representation of the business in the list along with the self link to the URI that would be in this example API/Businesses.

You should not confuse REST with the application of a specific URI naming convention.
HOW the resources are named is entirely secondary. You are trying to use HTTP resource naming conventions - this has nothing to do with REST. Roy Fielding himself states so repeatedly in the documents quoted above by others. REST is not a protocol, it is an architectural style.
In fact, Roy Fielding states in his 2008 blog comment (http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven 6/20/2012):
"A REST API must not define fixed resource names or hierarchies (an obvious coupling of
client and server). Servers must have the freedom to control their own namespace. Instead,
allow servers to instruct clients on how to construct appropriate URIs, such as is done in
HTML forms and URI templates, by defining those instructions within media types and link relations."
So in essence:
The problem you describe is not actually a problem of REST - conceptually, it is a problem of HIERARCHY STRUCTURES versus RELATIONAL STRUCTURES.
While a business is "in" a city and so can be considered to be part of the city "hierarchy" - what about international companies which have offices in 75 cities. Then the city suddenly becomes the junior element in a hierarchy with the business name at the senior level of the structure.
The point is, you can view data from various angles, and depending on the viewpoint you take, it may be simplest to see it as a hierarchy. But the same data can be seen as a hierarchy with different levels. When you are using HTTP type resource names, then you have entered a hierarchy structure defined by HTTP. This is a constraint, yes, but it's not a REST constraint, it's a HTTP constraint.
From that angle, you can chose the solution which fits better to your scenario. If your customer cannot supply the city name when he supplies the company name (he may not know), then it would be better to have the key with only city name. As I said, it's up to you, and REST won't stand in your way ...
More to the point:
The only real REST constraints you have, if you have already decided to use HTTP with GET
PUT and so on, are:
Thou shalt not presumeth any prior ("out of band") knowledge between client and servers. *
Look at your proposal #1 above in that light. You assume that customers know the keys for the cities which are contained in your system? Wrong - that's not restful. So the server has to give the list of cities as a list of choices in some way. So are you going to list every city in the world here?
I guess not, but then you'll have to do some work on how you are planning to do this, which brings us to:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state ...
I think, reading the mentioned Roy Fielding blog will help you out considerably.

In a RESTful-API URL design should be quite unimportant - or at least a side issue since the discoverability is encoded in the hypertext and not in the URL path. Have a look at the resources linked in the REST tag wiki here on StackOverflow.
But if you want to design human readable URLs for your UC, I would suggest the following:
Use the resource type you are creating/updating/querying as the first part of the URL (after your API prefix). So when somebody sees the URL he immediately knows to which resources this URL points. GET /Api/Employees... is the only only way to receive Employee resources from the API.
Use Unique IDs for each resource independent of the relations they are in. So GET /Api/<CollectionType>/UniqueKey should return a valid resource representation. Nobody should have to worry where the Employee is located. (But the returned Employee should have the links to the Business (and for convenience sake City) he belongs to.) GET /Api/Employees/Z6W returns the Employee with this ID no matter where is is located.
If you want to get a specific resource: Put your query parameter at the end (instead in the hierarchical order described in the question). You can use the URL query string (GET /Api/Employees?City=X7N) or a matrix parameter expression (GET /Api/Employees;City=X7N;Business=A4X,A5Y). This will allow you to easily express a collection of all Employees in a specific City - independent of the Business they are in.
Side node:
In my experience an initial hierarchical domain data model seldom survives additional requirements that come up during a project. In your case: Consider a business located in two Cities. You could create a workaround by modelling it as two separate businesses but what about the employee who works half his time in one place and the other half at the other location? Or even worse: It's only clear for which business he works but it's undefined, in which city?

The third way that I see is to make Businesses and Employees root resources and use query parameters to filter collections:
GET Api/Businesses?city=ABC (returns all Businesses in City ABC)
GET Api/Businesses/X7N (returns business X7N)
GET Api/Employees?businesses=X7N (returns all employees at business X7N)
PUT Api/Employees/WWW (updates employee WWW)
Your both solutions use concept of REST sub-resources which requires that subresource is included in parent resource so:
GET Api/City/ABC/Businesses
in response should also return data provided by:
GET Api/City/ABC/Businesses/X7N
GET Api/City/ABC/Businesses/X7N/Employees
similar for:
GET Api/Businesses/X7N
which should return data provided by:
GET Api/Businesses/X7N/Employees
It will make size of the response huge and time required to generate will increase.
To make REST API clean each resource should have only one bounded URI which fallow below patterns:
GET /resources
GET /resources/{id}
POST /resources
PUT /resources/{id}
If you need to make links between resources use HATEOAS

Go with example 1. I wouldn't worry about unnecessary information from the point of view of the server. A URL should clearly identify a resource in a unique fashion from the point of view of the client. If the client would not know what /Employee/12 means without first knowing that it is actually /Businesses/X7N/Employees/12 then the first URL seems redundant.
The client should be dealing with URLs rather than the individual parameters that make up the URLs, so there is nothing wrong with long URLs. To the client they are just strings. The server should be telling the client the URL to do what it needs to do, not the individual parameters that then require the client to construct the URL.

Related

How should I design a REST API

I'm thinking about a REST API design. There are several tables in my database. For example Customer and Order.
Of course - each Order has its Customer (and every customer can have many Orders).
I've decided to provide such an interface
/api/v1/Customers/ -- get list of Customers, add new Customer
/api/v1/Customers/:id: -- get Customer with id=:id:
/api/v1/Orders/ -- get list of Orders, add new Order
/api/v1/Orders/:id: -- get Order with id=:id:
It works flawlessly. But my frontend has to display a list of orders with customer names. With this interface, I will have to make a single call to /api/v1/Orders/ and then another call to /api/v1/Customer/:id: for each record from the previous call. Or perform two calls to /api/v1/Orders/ and /api/v1/Customers/ and combine them on the frontend side.
It looks like overkill, this kind of operation should be done at the database level. But how can/should I provide an appropriate interface?
/api/v1/OrdersWithCustomers
/api/v1/OrdersWithCustomers/:id:
Seems weir. Is it a right way to go
There's no rule that says you cannot "extend" the data being returned from a REST API call. So instead of returning "just" the Order entity (as stored in the backend), you could of course return an OrderResponseDTO which includes all (revelant) fields of the Order entity - plus some from the Customer entity that might are relevant in your use case.
The data model for your REST API does not have to be an exact 1:1 match to your underlying database schema - it does give you the freedom to leave out some fields, or add some additional information that the consumers of your API will find helpful.
Great question, and any API design will tend to hit pragmatic reality at some point like this.
One option is to include a larger object graph for each resource (ie include the customer linked to each order) but use filter query parameters to allow users to specify what properties they require or don't require.
Personally I think that request parameters on a restful GET are fine for either search semantics when retrieving a list of resources, or filtering what is presented for each resource as in this case
Another option for your use case might be to look into a GraphQL approach.
How would you do it on the web?
You've got a web site, and that website serves documents about Customers, and documents about Orders. But your clients aren't happy, because its too much boring, mistake-prone work to aggregate information in the two kinds of documents.
Can we please have a document, they ask, with the boring work already done?
And so you generate a bunch of these new reports, and stick them on your web server, and create links to make it easier to navigate between related documents. TA-DA.
A "REST-API" is a facade that makes your information look and act like a web site. The fact that you are generating your representations from a database is an implementation details, deliberately hidden behind the "uniform interface".

REST API design: how to handle resources that can also be sub-resources

I have to put a (read-only) REST service atop of an existing product database. The easy part is having a top level product resource, like:
/api/products/
Now, actually callers of this service will rather need to get their relevant products based on the ID of a store and of a specific process (like "retail"). Behind the scenes, the combination of those two values results in a configured subset of products. This must be transparent for the caller, it should not need to know about these "product portfolios".
So I thought about designing the URI like this, where 1234 is the StoreID and retail is the process:
/api/stores/1234/retail/products
The first question that comes up here is if I should return full products here or URIs to their individual resources on /api/products/ ... the pro would be clearly that the caller does not need to retrieve each individual product from /api/products, the con would be that this would cause a caching headache on the /api/stores/1234/retail/products URI.
To complicate things, those products of course also have prices. Also here, a product does not have one price, but multiple ones that is also dependent of the StoreID and the Process, besides other factors. In reality, prices are direct children of products, so:
/api/products/ABCD/prices
would be the obvious choice, but again, as StoreID and Process are relevant to pre-filter the prices, an URI like:
/api/stores/1234/retail/products/ABCD/prices
would be more appropriate.
At the same time, there are other subresources of products that will not make sense to have under this URI, like product details. Those would clearly only make sense directly under /api/products/ABCD/details as they are not dependant on the store or process.
But this looks somehow messy to me. But at the same time, solving this by only having queryparam filters to solve it directly on the product resource, is not much nicer and does not enforce the caller to provide both, StoreId and process:
/api/products?store=1234&process=retail
/api/products/ABCD/prices?store=1234&process=retail
Even more, process or storeid does not have anything to do with the product, so querying for it directly on product seems odd. For prices, it would make sense, though.
So my question is: is there a good way to solve this that i don't see? And: would you recommend returning full products when they are a subresource - and what do you think about handling (HTTP) caching when doing that?
The first question that comes up here is if I should return full
products here or URIs to their individual resources on /api/products/
[...] the con would be that this
would cause a caching headache on the /api/stores/1234/retail/products
URI.
I would definitely return the full products - imagine the amount the client would have to do if it would simply want to display a list of product names. Ideally this endpoint would be paginated (query string can include something like &pageSize=10&pageNumber=2, for example).
Also there are various caching solutions around this - for example you can cache all the products in a data structure service like Redis.
To complicate things, those products of course also have prices [...]
and details subresource.
Looking at the Richardson Maturity Model level 3, this would be where links come into play, and you could have something like this under a product resource:
<link rel = "/linkrels/products/ABCD/prices"
uri = "/products/ABCD/prices?store=1234&process=retail"/>
and another similar link for the product details resource.
#Roman is right, REST is meant to be discoverable, clients should simply follow links (that can have long/ugly uris), instead of having to memorize them (like in SOAP, for example).

REST URL Design for One to Many and Many to Many Relationships

Your backend has two Models:
One Company to Many Employees.
You want to accomplish the following:
Get all Companies
Get a Company by ID
Get all Employees for a Company
Get all Employees
Get a Employee by ID
What is the best practice for handling the REST URLs when your models have 1:M relationships? This is what I have thought of so far:
/companies/
/companies/<company_id>/
/companies/<company_id>/employees/
/employees/
/employees/id/<employee_id>/
Now let's pretend One Company has Many Models. What is the best name to use for "Adding an employee to a Company" ? I can think of several alternatives:
Using GET:
/companies/<company_id>/add-employee/<employee_id>/
/employees/<employee_id/add-company/<company_id>/
Using POST:
/companies/add-employee/
/employees/add-company/
The URIs look fine to me, except maybe the last one, that does not need an additional "id" in the path. Also, I prefer singular forms of words, but that is just me perhaps:
/company/
/company/<company_id>/
/company/<company_id>/employee/
/employee/
/employee/<employee_id>/
The URIs do not matter that much actually, and can be changed at any point later in time when done properly. That is, all the URIs are linked to, instead of hardcoded into the client.
As far as adding an employee, I would perhaps use the same URIs defined above, and the PUT method:
PUT /employee/123
With some representation of an employee. I would prefer the PUT because it is idempotent. This means, if the operation seems to fail (timeout, network error occurs, whatever) the operation can be repeated without checking whether the previous one "really" failed on the server or not. The PUT requires some additional work on the server side, and some additional work to properly link to (such as forms), but offers a more robust design.
As an alternative you can use
POST /employee
With the employee representation as body. This does not offer any guarantees, but it is easier to implement.
Do not use GET to add an employee (or anything for that matter). This would go against the HTTP Specification for the GET method, which states that it should be a pure information retrieval method.

RESTful services naming: GET the details of a list of products

I am trying to understand which should be the correct REST approach to name some of a e-commerce style endpoint.
If I am not mistaken, getting a list of products and the details of one of each will end up with two GET endpoints as
A) GET /products
B) GET /products/id
(I deliberately skipped pagination issues)
If I am looking at the list of shops which sell a specific product I can specify and endpoint as such
C) GET /products/id/shops
I struggle to understand though what happens if I need to specify more than one product for shop reserach.
Can the above endpoint be expanded to take multiple parameters or this is somehow discouraged?
In other words, should I be looking into something like
1) GET /products/id1,id2,id3/shops
2) GET /products/id1/shops [id2,id3]
or rather a completely new
3) GET /shops [id1,id2,id3]
?
Notes
Unanswered question in SO seems to underline that this is a sort of an untold story in RESTful services... :)
My current source of reference
As referred in many SO answers, as for example here, the URI does not make the service RESTful.
I agree with it, so to extend the concept a little my point above is that the implementation of the a service like 1) above may be (and in my case is, for server implementation details) different from easily combining the result given by 3 endpoints in the form of C).
In a more general sense, the implementation of such a combination could be kept internal.
Thus, yes the URI does not make the service RESTful but it would be nice to extend the cleaniness and expresiveness of the C) form for multiple ids.
Edit
In response to the correct note by Lutz in answer, shops may be trated as resources on their own.
What if, I came out with this not so clever example, the subresource does not really exists on its own, as for example the free places for 2 movies in a cinema where
GET /movies/12,14/places
where
GET /places?movies=12,14
is obviously feasible but not that RESTful imho.
I agree with the answer given by Lutz Horn. Furthermore, I'm not sure why you would think that using the query string in a GET request is "not that RESTful".
To quote from O'Reilly's RESTful Web Services, pg 233, under the header URI Design (emphasis mine):
Use punctuation characters to separate multiple pieces of data at the same level of hierarchy. Use commas when the order of the items matters, as it does in latitude and longitude: /Earth/37.0,-95.2. Use semicolons when the order doesn't matter: /color-blends/red;blue.
Use query variables only to suggest arguments being plugged into an algorithm, or when the other two techniques fail. If two URIs differ only in their query variables, it implies that they're the different sets of inputs into the same underlying algorithm.
This should give you sufficient direction in determining how to construct your routes. While you could easily construct it thusly (using semicolons, because it doesn't seem that order matters here):
GET /products/id1;id2;id3/shops
You could just as easily write it this way:
GET /shops?productIds=id1,id2,id3
And this might be a more reasonable approach given that what you indicate you are doing is searching for all shops that carry a particular item, and search is an algorithm for which product ids are input parameters.
To your example of movies (if I am understanding it correctly), if you are looking for places (our resource) where the movie (or movies) is showing AND seating is available:
GET /places?movie=id1,id2,id3&availability=true
It looks like you just have additional search parameters. If I am misunderstanding your "subresource may not exist" comment, please clarify this for us so that we can address it properly.
I would make shops a separate resource.
GET /shops lists all shops
GET /shops/123 gets the details of shop 123
GET /shops?sellsProduct=id1,id2,id3 lists all shop that sell the products
In URLs like /products/id/shops the shops are a subresource of a product. But since a shop can exist independently of any product, this makes not much sense.

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

Some RESTful services use different resource URIs 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. Should we use plural or singular for resource creation? What should be the criteria while deciding that?
For me is better to have a schema that you can map directly to code (easy to automate), mainly because code is what is going to be at both ends.
GET /orders <---> orders
POST /orders <---> orders.push(data)
GET /orders/1 <---> orders[1]
PUT /orders/1 <---> orders[1] = data
GET /orders/1/lines <---> orders[1].lines
POST /orders/1/lines <---> orders[1].lines.push(data)
The premise of using /resources is that it is representing "all" resources. If you do a GET /resources, you will likely return the entire collection. By POSTing to /resources, you are adding to the collection.
However, the individual resources are available at /resource. If you do a GET /resource, you will likely error, as this request doesn't make any sense, whereas /resource/123 makes perfect sense.
Using /resource instead of /resources is similar to how you would do this if you were working with, say, a file system and a collection of files and /resource is the "directory" with the individual 123, 456 files in it.
Neither way is right or wrong, go with what you like best.
I don't see the point in doing this either and I think it is not the best URI design. As a user of a RESTful service I'd expect the list resource to have the same name no matter whether I access the list or specific resource 'in' the list. You should use the same identifiers no matter whether you want use the list resource or a specific resource.
Plural
Simple - all urls start with the same prefix
Logical - orders/ gets an index list of orders.
Standard - Most widely adopted standard followed by the overwhelming majority of public and private APIs.
For example:
GET /resources - returns a list of resource items
POST /resources - creates one or many resource items
PUT /resources - updates one or many resource items
PATCH /resources - partially updates one or many resource items
DELETE /resources - deletes all resource items
And for single resource items:
GET /resources/:id - returns a specific resource item based on :id parameter
POST /resources/:id - creates one resource item with specified id (requires validation)
PUT /resources/:id - updates a specific resource item
PATCH /resources/:id - partially updates a specific resource item
DELETE /resources/:id - deletes a specific resource item
To the advocates of singular, think of it this way: Would you ask a someone for an order and expect one thing, or a list of things? So why would you expect a service to return a list of things when you type /order?
Singular
Convenience
Things can have irregular plural names. Sometimes they don't have one.
But Singular names are always there.
e.g. CustomerAddress over CustomerAddresses
Consider this related resource.
This /order/12/orderdetail/12 is more readable and logical than /orders/12/orderdetails/4.
Database Tables
A resource represents an entity like a database table.
It should have a logical singular name.
Here's the answer over table names.
Class Mapping
Classes are always singular. ORM tools generate tables with the same names as class names. As more and more tools are being used, singular names are becoming a standard.
Read more about A REST API Developer's Dilemma
For things without singular names
In the case of trousers and sunglasses, they don't seem to have a singular counterpart. They are commonly known and they appear to be singular by use. Like a pair of shoes. Think about naming the class file Shoe or Shoes. Here these names must be considered as a singular entity by their use. You don't see anyone buying a single shoe to have the URL as
/shoe/23
We have to see Shoes as a singular entity.
Reference: Top 6 REST Naming Best Practices
Why not follow the prevalent trend of database table names, where a singular form is generally accepted? Been there, done that -- let's reuse.
Table Naming Dilemma: Singular vs. Plural Names
Whereas the most prevalent practice are RESTful apis where plurals are used e.g. /api/resources/123 , there is one special case where I find use of a singular name more appropriate/expressive than plural names. It is the case of one-to-one relationships. Specifically if the target item is a value object(in Domain-driven-design paradigm).
Let us assume every resource has a one-to-one accessLog which could be modeled as a value object i.e not an entity therefore no ID. It could be expressed as /api/resources/123/accessLog. The usual verbs (POST, PUT, DELETE, GET) would appropriately express the intent and also the fact that the relationship is indeed one-to-one.
I am surprised to see that so many people would jump on the plural noun bandwagon. When implementing singular to plural conversions, are you taking care of irregular plural nouns? Do you enjoy pain?
See
http://web2.uvcs.uvic.ca/elc/studyzone/330/grammar/irrplu.htm
There are many types of irregular plural, but these are the most common:
Noun type Forming the plural Example
Ends with -fe Change f to v then Add -s
knife knives
life lives
wife wives
Ends with -f Change f to v then Add -es
half halves
wolf wolves
loaf loaves
Ends with -o Add -es
potato potatoes
tomato tomatoes
volcano volcanoes
Ends with -us Change -us to -i
cactus cacti
nucleus nuclei
focus foci
Ends with -is Change -is to -es
analysis analyses
crisis crises
thesis theses
Ends with -on Change -on to -a
phenomenon phenomena
criterion criteria
ALL KINDS Change the vowel or Change the word or Add a different ending
man men
foot feet
child children
person people
tooth teeth
mouse mice
Unchanging Singular and plural are the same
sheep deer fish (sometimes)
From the API consumer's perspective, the endpoints should be predictable so
Ideally...
GET /resources should return a list of resources.
GET /resource should return a 400 level status code.
GET /resources/id/{resourceId} should return a collection with one resource.
GET /resource/id/{resourceId} should return a resource object.
POST /resources should batch create resources.
POST /resource should create a resource.
PUT /resource should update a resource object.
PATCH /resource should update a resource by posting only the changed attributes.
PATCH /resources should batch update resources posting only the changed attributes.
DELETE /resources should delete all resources; just kidding: 400 status code
DELETE /resource/id/{resourceId}
This approach is the most flexible and feature rich, but also the most time consuming to develop. So, if you're in a hurry (which is always the case with software development) just name your endpoint resource or the plural form resources. I prefer the singular form because it gives you the option to introspect and evaluate programmatically since not all plural forms end in 's'.
Having said all that, for whatever reason the most commonly used practice developer's have chosen is to use the plural form. This is ultimately the route I have chosen and if you look at popular apis like github and twitter, this is what they do.
Some criteria for deciding could be:
What are my time constraints?
What operations will I allow my consumers to do?
What does the request and result payload look like?
Do I want to be able to use reflection and parse the URI in my code?
So it's up to you. Just whatever you do be consistent.
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
My two cents: methods who spend their time changing from plural to singular or viceversa are a waste of CPU cycles. I may be old-school, but in my time like things were called the same. How do I look up methods concerning people? No regular expresion will cover both person and people without undesirable side effects.
English plurals can be very arbitrary and they encumber the code needlessly. Stick to one naming convention. Computer languages were supposed to be about mathematical clarity, not about mimicking natural language.
I prefer using singular form for both simplicity and consistency.
For example, considering the following url:
/customer/1
I will treat customer as customer collection, but for simplicity, the collection part is removed.
Another example:
/equipment/1
In this case, equipments is not the correct plural form. So treating it as a equipment collection and removing collection for simplicity makes it consistent with the customer case.
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
they have exceptions like one of something being called by the plural form, and
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:
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.
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.
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.
With naming conventions, it's usually safe to say "just pick one and stick to it", which makes sense.
However, after having to explain REST to lots of people, representing endpoints as paths on a file system is the most expressive way of doing it.
It is stateless (files either exist or don't exist), hierarchical, simple, and familiar - you already knows how to access static files, whether locally or via http.
And within that context, linguistic rules can only get you as far as the following:
A directory can contain multiple files and/or sub-directories, and therefore its name should be in plural form.
And I like that.
Although, on the other hand - it's your directory, you can name it "a-resource-or-multiple-resources" if that's what you want. That's not really the important thing.
What's important is that if you put a file named "123" under a directory named "resourceS" (resulting in /resourceS/123), you cannot then expect it to be accessible via /resource/123.
Don't try to make it smarter than it has to be - changing from plural to singluar depending on the count of resources you're currently accessing may be aesthetically pleasing to some, but it's not effective and it doesn't make sense in a hierarchical system.
Note: Technically, you can make "symbolic links", so that /resources/123 can also be accessed via /resource/123, but the former still has to exist!
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.
I know most people are between deciding whether to use plural or singular. The issue that has not been addressed here is that the client will need to know which one you are using, and they are always likely to make a mistake. This is where my suggestion comes from.
How about both? And by that, I mean use singular for your whole API and then create routes to forward requests made in the plural form to the singular form. For example:
GET /resources = GET /resource
GET /resources/1 = GET /resource/1
POST /resources/1 = POST /resource/1
...
You get the picture. No one is wrong, minimal effort, and the client will always get it right.
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:
https://restfulapi.net/resource-naming/
Using plural for all methods is more practical at least in one aspect:
if you're developing and testing a resource API using Postman (or similar tool), you don't need to edit the URI when switching from GET to PUT to POST etc.
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.
Both representations are useful. I had used singular for convenience for quite some time, inflection can be difficult. My experience in developing strictly singular REST APIs, the developers consuming the endpoint lack certainty in what the shape of the result may be. I now prefer to use the term that best describes the shape of the response.
If all of your resources are top level, then you can get away with singular representations. Avoiding inflection is a big win.
If you are doing any sort of deep linking to represent queries on relations, then developers writing against your API can be aided by having a stricter convention.
My convention is that each level of depth in a URI is describing an interaction with the parent resource, and the full URI should implicitly describe what is being retrieved.
Suppose we have the following model.
interface User {
<string>id;
<Friend[]>friends;
<Manager>user;
}
interface Friend {
<string>id;
<User>user;
...<<friendship specific props>>
}
If I needed to provide a resource that allows a client to get the manager of a particular friend of a particular user, it might look something like:
GET /users/{id}/friends/{friendId}/manager
The following are some more examples:
GET /users - list the user resources in the global users collection
POST /users - create a new user in the global users collection
GET /users/{id} - retrieve a specific user from the global users collection
GET /users/{id}/manager - get the manager of a specific user
GET /users/{id}/friends - get the list of friends of a user
GET /users/{id}/friends/{friendId} - get a specific friend of a user
LINK /users/{id}/friends - add a friend association to this user
UNLINK /users/{id}/friends - remove a friend association from this user
Notice how each level maps to a parent that can be acted upon. Using different parents for the same object is counterintuitive. Retrieving a resource at GET /resource/123 leaves no indication that creating a new resource should be done at POST /resources
To me plurals manipulate the collection, whereas singulars manipulate the item inside that collection.
Collection allows the methods GET / POST / DELETE
Item allows the methods GET / PUT / DELETE
For example
POST on /students will add a new student in the school.
DELETE on /students will remove all the students in the school.
DELETE on /student/123 will remove student 123 from the school.
It might feel like unimportant but some engineers sometimes forget the id. If the route was always plural and performed a DELETE, you might accidentally wipe your data. Whereas missing the id on the singular will return a 404 route not found.
To further expand the example if the API was supposed to expose multiple schools, then something like
DELETE on /school/abc/students will remove all the students in the school abc.
Choosing the right word sometimes is a challenge on its own, but I like to maintain plurality for the collection. E.g. cart_items or cart/items feels right. In contrast deleting cart, deletes the cart object it self and not the items within the cart ;).
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".
Just be consistent.
Use either singular:
POST /resource
PUT /resource/123
GET /resource/123
or plural:
POST /resources
PUT /resources/123
GET /resources/123
I prefer to use both plural (/resources) and singular (/resource/{id}) because I think that it more clearly separates the logic between working on the collection of resources and working on a single resource.
As an important side-effect of this, it can also help to prevent somebody using the API wrongly. For example, consider the case where a user wrongly tries to get a resource by specifying the Id as a parameter like this:
GET /resources?Id=123
In this case, where we use the plural version, the server will most likely ignore the Id parameter and return the list of all resources. If the user is not careful, he will think that the call was successful and use the first resource in the list.
On the other hand, when using the singular form:
GET /resource?Id=123
the server will most likely return an error because the Id is not specified in the right way, and the user will have to realize that something is wrong.