Is it ok to nest REST resources in "directories" that indicate the resources are of a similar type, as opposed to indicating a belongs-to hierarchy? - rest

It's common to nest resources in a RESTful API. For example, to retrieve the employees in company having ID=5:
GET /companies/5/employees
Is it also generally acceptable in a REST design to put resources in a common "directory" where they don't really belong-to a common parent resource instance? This is more of a "is-a" relationship, where I think the typical nested structure has the nested resources in a "belongs-to" relationship.
For example, is it acceptable to group two different resources (internal agents, external agents) like follows? In this case the agents part of the path is a category that describes its descendants but isn't really a parent resource.
GET /agents/internal
GET /agents/external
There are no plans to add any resources using the /agents path; it is solely for grouping purposes.
Or is that to be avoided for something like this?
GET /internal-agents
GET /external-agents
I feel like the second option is more correct, but there is an aesthetic to the first option that that I like.

Given that you have some agents which can be internal or external:
/agents/internal is a terrible idea breaking URL consistency
/internal-agents is a valid idea but beware of drawbacks
A filter could be better for this use case: GET /agents?status=internal
/agents/internal is a terrible idea breaking URL consistency
Having /agents/internal is a terrible idea, it MUST not be used as it will lead to inconsistent URLs in your API which will not be easily understand by humans but also programs.
The best pattern for REST URL (exluding domain and versioning matters) is this one: /resources/{resouce id}/sub-resources/{sub-resource id}// No more than 2 levels should be allowed.
Your first example /companies/5/employees is a perfect good example.
Adding a /agents/internal URL will make your API's URLs inconsistent and difficult to understand for humans but also programs. You can end having GET /agents/2 which return agent with id 2 and also GET /agents/internal which return a list of internal agents. Same URL structure but different meanings.
Using a consistent structure for URL helps to understand the semantic without even knowing what an API does.
/internal-agents is a valid idea but beware of drawbacks
Your idea of having two specific resources internal-agents and external-agents is valid.
But it can have some drawbacks depending on the exact use case:
if you add more status, like partner for example, you'll have to add a new resource partner-agents
if a consumer want to retrieve both type it'll have to make to calls or you'll have to create a /agents resource
A filter could be better for this use case: GET /agents?status=internal
A third idea would be to consider internal and external as filter on some status on /agents resource.
GET /agents returns all agents (internal + external)
GET /agents/2 returns agent with id 2
GET /agents?status=internal returns agents with internal status
GET /agents?status=external returns agents with external status
And if you add a new status like partner:
GET /agents returns all agents (internal + external + new partner status)
GET /agents/2 still returns agent with id 2
GET /agents?status=internal still returns agents with internal status
GET /agents?status=external still returns agents with external status
GET /agents?status=partner returns agents with new partner status
GET /agents?status=internal,partner returns agents with internal or partner status
Choosing between filter and specific resources is only a metter of context.
The only thing to keep in mind is to ensure URLs consistency.

Related

REST resource for checking if a resource has existing subresources

My application provides the following resource:
GET /user/:id/orders
As commonly used, this returns a list of all the user's orders.
Now, a client wants to check if a user has any orders at all without actually getting the complete list.
My current approach looks like this:
GET /user/:id/orders/exist
But it looks kind of odd to me.
Is there a more "standard" way of designing this? In the end, this resource only needs to return the information:
yes, user has orders
no, user doesn't have any orders
What you will see in some API is the notion of a resource that exists (204) or does not exist (404).
But I really don't recommend that: saving a few bytes in your representation of the resource doesn't help very much when you are already sending a response-line and a bunch of HTTP headers.
Your "resource model" can be anything you want.
The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction -- Fielding, 2000
So you can create fine grained resources if you like; but there are can be consequences to that. "Tradeoffs" are a thing.
Resources are generalizations of "documents"; if it makes sense to have a report that is just a count of the number of orders, or a statement that the number of orders is greater than zero, or whatever, then that report can certainly be a resource in your resource model.
If you know what the report is, then you might be able to guess at a name for the report, and from there to a spelling for it.
There's no particular reason that the report identifier has to be part of the /user hierarchy; the machines don't care what spelling conventions you use.
/user/:id/orders/report
/user/:id/orders-report
/user/:id/report
/report/:id
/report?user=:id
/report/user=:id
Those are all fine; choose whichever variation is appropriate to your local conventions.
Note that you want to be aware of caching - when you have information in two different resources, it is easy for the client's locally cached copies to contradict each other (report says that there are orders, but the orders list is empty; or the other way around). As far as REST, and general purpose components are concerned, different resources are different, and vary independently of each other.
In the large grained world, you don't have that problem so often, because you throw the kitchen sink into a single resource; as long as its produced representations are internally consistent, the cached copies will be as well.

Designing a REST api by URI vs query string

Let's say I have three resources that are related like so:
Grandparent (collection) -> Parent (collection) -> and Child (collection)
The above depicts the relationship among these resources like so: Each grandparent can map to one or several parents. Each parent can map to one or several children. I want the ability to support searching against the child resource but with the filter criteria:
If my clients pass me an id reference to a grandparent, I want to only search against children who are direct descendants of that grandparent.
If my clients pass me an id reference to a parent, I want to only search against children who are direct descendants of my parent.
I have thought of something like so:
GET /myservice/api/v1/grandparents/{grandparentID}/parents/children?search={text}
and
GET /myservice/api/v1/parents/{parentID}/children?search={text}
for the above requirements, respectively.
But I could also do something like this:
GET /myservice/api/v1/children?search={text}&grandparentID={id}&parentID=${id}
In this design, I could allow my client to pass me one or the other in the query string: either grandparentID or parentID, but not both.
My questions are:
1) Which API design is more RESTful, and why? Semantically, they mean and behave the same way. The last resource in the URI is "children", effectively implying that the client is operating on the children resource.
2) What are the pros and cons to each in terms of understandability from a client's perspective, and maintainability from the designer's perspective.
3) What are query strings really used for, besides "filtering" on your resource? If you go with the first approach, the filter parameter is embedded in the URI itself as a path parameter instead of a query string parameter.
Thanks!
Something to note, is that since you use GET in your above examples,
dependant on the end user browser settings, proxy settings or other calling applications internal settings,
the response is likely to be cached somewhere on the message route, and the original request message may never actually reach your API layer where the most recent data is accessed.
so first, you may want to review your requirement of using the verb GET.
If you want your API to return the most recent data every time, then don't use GET, or if you still want to use GET, then require the caller to append a random number to the end of the url, to decrease the likely hood of caching.
or get the client to send the verb PURGE, after every GET.
this proxy caching behaviour that is present across the internet, in browsers, and server architectures is where REST fails for me, since caching of GET can be very useful but only sometimes.
stick to basic querystrings if you want to make it really simple for the end developer and caching of responses offers no problems for you,
or
just use POST and forget about this tiresome REST argument

REST Resources, should they be client specific, server specific or both?

I have a use case where for a same entity, there are 2 identifiers, and each of them can map to the entity if used separately. 1 identifier is client friendly (say c_id), and the other is server friendly (say s_id). Clients do know the s_id, but in most cases they wont use it. And server knows both the ids, but the implementation on server is such that every thing is easily mapped using s_id.
In such a case, is it a good practice to provide resources on both c_id & s_id level, where the resource name and id (in input) will differ and will do the same thing, or should it be only a single resource, which also leads to the debate that which resource should be used.
I would normally have the resources existing under their server identities, and then provide search methods that return 302 redirects (or 307 if you prefer) to the appropriate resources. The clients would use these search/query methods to arrive at the correct resources.
Because the server "owns" the resources (and their URLs), it's fine for it to arrive at the resources by URL-fiddling. Whereas, because the clients shouldn't engage in URL-fiddling to find resources, giving them a query method where they can specify the ID(s) they know as query string parameters feels cleaner.
Your API exists for the benefit of its users. You should always strive to make it as easy as possible for them. If unique client-friendly IDs exist for all resources, then make your API work against the client-friendly ID. Your API can store a map from clientId to serverId in memory and easily switch to the ID it's more comfortable with.
If there aren't unique client-friendly IDs for all resources, you've got a pickle. I'd start by trying to close the gap (ie give the remaining resources clientIds). If that's not an option, then I agree with Damien.
What I often do is create the canonical URI as the one with the s_id, so something like,
http://example.org/api/foo/{s_id}
and then provide a search facility that allows searching by c_id, and potentially other attributes.
http://examples.org/api/foos?c_id={c_id}
This can return a list of foos, each with a link to the s_id URI. Or if, as in your case, only one foo returns, then you could either redirect to the canonical URI, or you can actually return the full foo representation and set the Content-Location header to the canonical URI.

Looking for RESTful approach to update multiple resources with the same field set

The task: I have multiple resources that need to be updated in one HTTP call.
The resource type, field and value to update are the same for all resources.
Example: have set of cars by their IDs, need to update "status" of all cars to "sold".
Classic RESTFul approach: use request URL something like
PUT /cars
with JSON body like
[{id:1,status:sold},{id:2,status:sold},...]
However this seems to be an overkill: too many times to put status:sold
Looking for a RESTful way (I mean the way that is as close to "standard" rest protocol as possible) to send status:sold just once for all cars along with the list of car IDs to update. This is what I would do:
PUT /cars
With JSON
{ids=[1,2,...],status:sold} but I am not sure if this is truly RESTful approach.
Any ideas?
Also as an added benefit: I would like to be able to avoid JSON for small number of cars by simply setting up a URL with parameters something like this:
PUT /cars?ids=1,2,3&status=sold
Is this RESTful enough?
An even simpler way would just be:
{sold:[1,2,...]}
There's no need to have multiple methods for larger or smaller numbers of requests - it wastes development time and has no noteable impact upon performance or bandwidth.
As far as it being RESTful goes, as long as it's easily decipherable by the recipient and contains all the information you need, then there's no problem with it.
As I understand it using put is not sufficient to write a single property of a resource. One idea is to simply expose the property as a resource itself:
Therefore: PUT /car/carId/status with body content 'Sold'.
Updating more than one car should result in multiple puts since a request should only target a single resource.
Another Idea is to expose a certain protocol where you build a 'batch' resource.
POST /daily-deals-report/ body content {"sold" : [1, 2, 3, 4, 5]}
Then the system can simply acknowledge the deals being made and update the cars status itself. This way you create a whole new point of view and enable a more REST like api then you actually intended.
Also you should think about exposing a resource listing all cars that are available and therefore are ready for being sold (therefore not sold, and not needing repairs or are not rent).
GET /cars/pricelist?city=* -> List of all cars ready to be sold including car id and price.
This way a car do not have a status regarding who is owning the car. A resource is usually independent of its owner (owner is aggregating cars not a composite of it).
Whenever you have difficulties to map an operation to a resource your model tend to be flawed by object oriented thinking. With resources many relations (parent property) and status properties tend to be misplaced since designing resources is even more abstract than thinking in services.
If you need to manipulate many similar objects you need to identify the business process that triggers those changes and expose this process by a single resource describing its input (just like the daily deals report).

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.