What are best practices for REST nested resources?
up vote
210
down vote
favorite
As far as I can tell each individual resource should have only one canonical path. So in the following example what would good URL patterns be?
Take for an example a rest representation of Companies. In this hypothetical example, each company owns 0 or more departments and each department owns 0 or more employees.
A department can't exist without an associated company.
An employee can't exist without an associated department.
Now I'd find the natural representation of the resource patterns to be.
/companies
A collection of companies - Accepts put for a new company. Get for the entire collection.
/companies/{companyId}
An individual company. Accepts GET, PUT and DELETE
/companies/{companyId}/departments
Accepts POST for a new item. (Creates a department within the company.)/companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Given the constraints, in each of the sections, I feel that this makes sense if a bit deeply nested.
However, my difficulty comes if I want to list (GET
) all employees across all companies.
The resource pattern for that would most closely map to /employees
(The collection of all employees)
Does that mean that I should have /employees/{empId}
also because if so then there are two URI's to get the same resource?
Or maybe the entire schema should be flattened but that would mean that employees are a nested top-level object.
At a basic level /employees/?company={companyId}&department={deptId}
returns the exact same view of employees as the most deeply nested pattern.
What's the best practice for URL patterns where resources are owned by other resources but should be query-able separately?
UPDATE: See my answer below to see what I've done.
rest api-design
add a comment |
up vote
210
down vote
favorite
As far as I can tell each individual resource should have only one canonical path. So in the following example what would good URL patterns be?
Take for an example a rest representation of Companies. In this hypothetical example, each company owns 0 or more departments and each department owns 0 or more employees.
A department can't exist without an associated company.
An employee can't exist without an associated department.
Now I'd find the natural representation of the resource patterns to be.
/companies
A collection of companies - Accepts put for a new company. Get for the entire collection.
/companies/{companyId}
An individual company. Accepts GET, PUT and DELETE
/companies/{companyId}/departments
Accepts POST for a new item. (Creates a department within the company.)/companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Given the constraints, in each of the sections, I feel that this makes sense if a bit deeply nested.
However, my difficulty comes if I want to list (GET
) all employees across all companies.
The resource pattern for that would most closely map to /employees
(The collection of all employees)
Does that mean that I should have /employees/{empId}
also because if so then there are two URI's to get the same resource?
Or maybe the entire schema should be flattened but that would mean that employees are a nested top-level object.
At a basic level /employees/?company={companyId}&department={deptId}
returns the exact same view of employees as the most deeply nested pattern.
What's the best practice for URL patterns where resources are owned by other resources but should be query-able separately?
UPDATE: See my answer below to see what I've done.
rest api-design
1
This is almost exactly the oppsite problem to that described in stackoverflow.com/questions/7104578/… though the answers may be related. Both questions are about ownership but that example implies that the top level object isn't the owning one.
– Wes
Jan 6 '14 at 13:55
1
Exactly what I was wondering about. For the given use case your solution seems fine, but what if the relation is an aggregation rather than a composition? Still struggling to figure out what the best practice is here... Also, does this solution imply only the creation of the relationship, e.g. an existing person is employed or does it create a person object?
– Jakob O.
Mar 28 '14 at 10:32
It creates a person in my fictitious example. The reason I used those domain terms is its a reasonably understandable example, though mimicking my actual problem. Have you looked through the linked question that may halp you more for an aggragation relationship.
– Wes
Apr 8 '14 at 13:05
I've split my question into an answer and a question.
– Wes
Sep 28 '15 at 10:30
I'm voting to close this question as off-topic because its about a pattern rather than a programming problem and has gathered too many votes.
– Wes
Oct 26 '17 at 23:15
add a comment |
up vote
210
down vote
favorite
up vote
210
down vote
favorite
As far as I can tell each individual resource should have only one canonical path. So in the following example what would good URL patterns be?
Take for an example a rest representation of Companies. In this hypothetical example, each company owns 0 or more departments and each department owns 0 or more employees.
A department can't exist without an associated company.
An employee can't exist without an associated department.
Now I'd find the natural representation of the resource patterns to be.
/companies
A collection of companies - Accepts put for a new company. Get for the entire collection.
/companies/{companyId}
An individual company. Accepts GET, PUT and DELETE
/companies/{companyId}/departments
Accepts POST for a new item. (Creates a department within the company.)/companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Given the constraints, in each of the sections, I feel that this makes sense if a bit deeply nested.
However, my difficulty comes if I want to list (GET
) all employees across all companies.
The resource pattern for that would most closely map to /employees
(The collection of all employees)
Does that mean that I should have /employees/{empId}
also because if so then there are two URI's to get the same resource?
Or maybe the entire schema should be flattened but that would mean that employees are a nested top-level object.
At a basic level /employees/?company={companyId}&department={deptId}
returns the exact same view of employees as the most deeply nested pattern.
What's the best practice for URL patterns where resources are owned by other resources but should be query-able separately?
UPDATE: See my answer below to see what I've done.
rest api-design
As far as I can tell each individual resource should have only one canonical path. So in the following example what would good URL patterns be?
Take for an example a rest representation of Companies. In this hypothetical example, each company owns 0 or more departments and each department owns 0 or more employees.
A department can't exist without an associated company.
An employee can't exist without an associated department.
Now I'd find the natural representation of the resource patterns to be.
/companies
A collection of companies - Accepts put for a new company. Get for the entire collection.
/companies/{companyId}
An individual company. Accepts GET, PUT and DELETE
/companies/{companyId}/departments
Accepts POST for a new item. (Creates a department within the company.)/companies/{companyId}/departments/{departmentId}/
/companies/{companyId}/departments/{departmentId}/employees
/companies/{companyId}/departments/{departmentId}/employees/{empId}
Given the constraints, in each of the sections, I feel that this makes sense if a bit deeply nested.
However, my difficulty comes if I want to list (GET
) all employees across all companies.
The resource pattern for that would most closely map to /employees
(The collection of all employees)
Does that mean that I should have /employees/{empId}
also because if so then there are two URI's to get the same resource?
Or maybe the entire schema should be flattened but that would mean that employees are a nested top-level object.
At a basic level /employees/?company={companyId}&department={deptId}
returns the exact same view of employees as the most deeply nested pattern.
What's the best practice for URL patterns where resources are owned by other resources but should be query-able separately?
UPDATE: See my answer below to see what I've done.
rest api-design
rest api-design
edited Nov 8 at 11:20
asked Jan 6 '14 at 13:51
Wes
2,48422350
2,48422350
1
This is almost exactly the oppsite problem to that described in stackoverflow.com/questions/7104578/… though the answers may be related. Both questions are about ownership but that example implies that the top level object isn't the owning one.
– Wes
Jan 6 '14 at 13:55
1
Exactly what I was wondering about. For the given use case your solution seems fine, but what if the relation is an aggregation rather than a composition? Still struggling to figure out what the best practice is here... Also, does this solution imply only the creation of the relationship, e.g. an existing person is employed or does it create a person object?
– Jakob O.
Mar 28 '14 at 10:32
It creates a person in my fictitious example. The reason I used those domain terms is its a reasonably understandable example, though mimicking my actual problem. Have you looked through the linked question that may halp you more for an aggragation relationship.
– Wes
Apr 8 '14 at 13:05
I've split my question into an answer and a question.
– Wes
Sep 28 '15 at 10:30
I'm voting to close this question as off-topic because its about a pattern rather than a programming problem and has gathered too many votes.
– Wes
Oct 26 '17 at 23:15
add a comment |
1
This is almost exactly the oppsite problem to that described in stackoverflow.com/questions/7104578/… though the answers may be related. Both questions are about ownership but that example implies that the top level object isn't the owning one.
– Wes
Jan 6 '14 at 13:55
1
Exactly what I was wondering about. For the given use case your solution seems fine, but what if the relation is an aggregation rather than a composition? Still struggling to figure out what the best practice is here... Also, does this solution imply only the creation of the relationship, e.g. an existing person is employed or does it create a person object?
– Jakob O.
Mar 28 '14 at 10:32
It creates a person in my fictitious example. The reason I used those domain terms is its a reasonably understandable example, though mimicking my actual problem. Have you looked through the linked question that may halp you more for an aggragation relationship.
– Wes
Apr 8 '14 at 13:05
I've split my question into an answer and a question.
– Wes
Sep 28 '15 at 10:30
I'm voting to close this question as off-topic because its about a pattern rather than a programming problem and has gathered too many votes.
– Wes
Oct 26 '17 at 23:15
1
1
This is almost exactly the oppsite problem to that described in stackoverflow.com/questions/7104578/… though the answers may be related. Both questions are about ownership but that example implies that the top level object isn't the owning one.
– Wes
Jan 6 '14 at 13:55
This is almost exactly the oppsite problem to that described in stackoverflow.com/questions/7104578/… though the answers may be related. Both questions are about ownership but that example implies that the top level object isn't the owning one.
– Wes
Jan 6 '14 at 13:55
1
1
Exactly what I was wondering about. For the given use case your solution seems fine, but what if the relation is an aggregation rather than a composition? Still struggling to figure out what the best practice is here... Also, does this solution imply only the creation of the relationship, e.g. an existing person is employed or does it create a person object?
– Jakob O.
Mar 28 '14 at 10:32
Exactly what I was wondering about. For the given use case your solution seems fine, but what if the relation is an aggregation rather than a composition? Still struggling to figure out what the best practice is here... Also, does this solution imply only the creation of the relationship, e.g. an existing person is employed or does it create a person object?
– Jakob O.
Mar 28 '14 at 10:32
It creates a person in my fictitious example. The reason I used those domain terms is its a reasonably understandable example, though mimicking my actual problem. Have you looked through the linked question that may halp you more for an aggragation relationship.
– Wes
Apr 8 '14 at 13:05
It creates a person in my fictitious example. The reason I used those domain terms is its a reasonably understandable example, though mimicking my actual problem. Have you looked through the linked question that may halp you more for an aggragation relationship.
– Wes
Apr 8 '14 at 13:05
I've split my question into an answer and a question.
– Wes
Sep 28 '15 at 10:30
I've split my question into an answer and a question.
– Wes
Sep 28 '15 at 10:30
I'm voting to close this question as off-topic because its about a pattern rather than a programming problem and has gathered too many votes.
– Wes
Oct 26 '17 at 23:15
I'm voting to close this question as off-topic because its about a pattern rather than a programming problem and has gathered too many votes.
– Wes
Oct 26 '17 at 23:15
add a comment |
6 Answers
6
active
oldest
votes
up vote
105
down vote
accepted
What you have done is correct. In general there can be many URIs to the same resource - there are no rules that say you shouldn't do that.
And generally, you may need to access items directly or as a subset of something else - so your structure makes sense to me.
Just because employees are accessible under department:
company/{companyid}/department/{departmentid}/employees
Doesn't mean they can't be accessible under company too:
company/{companyid}/employees
Which would return employees for that company. It depends on what is needed by your consuming client - that is what you should be designing for.
But I would hope that all URLs handlers use the same backing code to satisfy the requests so that you aren't duplicating code.
9
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
9
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.
– max
Jul 3 '16 at 5:02
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.
– kashif
Oct 2 '17 at 3:57
|
show 1 more comment
up vote
103
down vote
I've tried both design strategies - nested and non-nested endpoints. I've found that:
if the nested resource has a primary key and you don't have its parent primary key, the nested structure requires you to get it, even though the system doesn't actually require it.
nested endpoints typically require redundant endpoints. In other words, you will more often than not, need the additional /employees endpoint so you can get a list of employees across departments. If you have /employees, what exactly does /companies/departments/employees buy you?
nesting endpoints don't evolve as nicely. E.g. you might not need to search for employees now but you might later and if you have a nested structure, you have no choice but to add another endpoint. With a non-nested design, you just add more parameters, which is simpler.
sometimes a resource could have multiple types of parents. Resulting in multiple endpoints all returning the same resource.
redundant endpoints makes the docs harder to write and also makes the api harder to learn.
In short, the non-nested design seems to allow a more flexible and simpler endpoint schema.
11
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
3
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
3
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
1
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
add a comment |
up vote
53
down vote
I've moved what I've done from the question to an answer where more people are likely to see it.
What I've done is to have the creation endpoints at the nested endpoint, The canonical endpoint for modifying or querying an item is not at the nested resource.
So in this example (just listing the endpoints that change a resource)
POST
/companies/
creates a new company returns a link to the created company.
POST
/companies/{companyId}/departments
when a department is put creates the new department returns a link to/departments/{departmentId}
PUT
/departments/{departmentId}
modifies a department
POST
/departments/{deparmentId}/employees
creates a new employee returns a link to/employees/{employeeId}
So there are root level resources for each of the collections. However the create is in the owning object.
2
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I guess you usedPOST
meaningPUT
, and otherwise.
– Gerardo Lima
Jan 18 at 15:43
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
|
show 4 more comments
up vote
6
down vote
I disagree with this kind of path
GET /companies/{companyId}/departments
If you want to get departments, I think it's better to use a /departments resource
GET /departments?companyId=123
I suppose you have a companies
table and a departments
table then classes to map them in the programming language you use. I also assume that departments could be attached to other entities than companies, so a /departments resource is straightforward, it's convenient to have resources mapped to tables and also you don't need as many endpoints since you can reuse
GET /departments?companyId=123
for any kind of search, for instance
GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.
If you want to create a department, the
POST /departments
resource should be used and the request body should contain the company ID (if the department can be linked to only one company).
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
2
It may also make sense to allow departments to be included via lazy loading when fetching a company, egGET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.
– Matthew Daly
Jul 27 '17 at 11:31
When you're setting up acls you probably want to restrict the/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`
– Cuzox
Dec 26 '17 at 13:34
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
add a comment |
up vote
6
down vote
How your URLs look have nothing to do with REST. Anything goes. It actually is an "implementation detail". So just like how you name your variables. All they have to be is unique and durable.
Don't waste too much time on this, just make a choice and stick to it/be consistent. For example if you go with hierarchies then you do it for all your resources. If you go with query parameters...etc just like naming conventions in your code.
Why so ? As far as I know a "RESTful" API is to be browsable (you know..."Hypermedia as the Engine of Application State"), therefore an API client does not care about what your URLs are like as long as they're valid (there's no SEO, no human that needs to read those "friendly urls", except may be for debugging...)
How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be.
The most important thing is that your API client know how to interpret your media type.
For example it knows that :
- your media type has a links property that lists available/related links.
- Each link is identified by a relationship (just like browsers know that link[rel="stylesheet"] means its a style sheet or rel=favico is a link to a favicon...)
- and it knowns what those relationships mean ("companies" mean a list of companies,"search" means a templated url for doing a search on a list of resource, "departments" means departments of the current resource )
Below is an example HTTP exchange (bodies are in yaml since it's easier to write):
Request
GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml
Response: a list of links to main resource (companies, people, whatever...)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: this is your API's entrypoint (like a homepage)
links:
# could be some random path https://api.acme.local/modskmklmkdsml
# the only thing the API client cares about is the key (or rel) "companies"
companies: https://api.acme.local/companies
people: https://api.acme.local/people
Request: link to companies (using previous response's body.links.companies)
GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml
Response: a partial list of companies (under items), the resource contains related links, like link to get the next couple of companies (body.links.next) an other (templated) link to search (body.links.search)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: representation of a list of companies
links:
# link to the next page
next: https://api.acme.local/companies?page=2
# templated link for search
search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
add:
href: https://api.acme.local/companies
method: POST
items:
- name: company1
links:
self: https://api.acme.local/companies/8er13eo
# and here is the link to departments
# again the client only cares about the key department
department: https://api.acme.local/companies/8er13eo/departments
- name: company2
links:
self: https://api.acme.local/companies/9r13d4l
# or could be in some other location !
department: https://api2.acme.local/departments?company=8er13eo
So as you see if you go the links/relations way how you structure the path part of your URLs does't have any value to your API client. And if your are communicating the structure of your URLs to your client as documentation, then your are not doing REST (or at least not Level 3 as per "Richardson's maturity model")
6
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
1
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
3
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
add a comment |
up vote
5
down vote
I've read all of above answer but seem like have no common strategy. I found a good article about best practices in Design API from Microsoft Documents. I think you should refer.
In more complex systems, it can be tempting to provide URIs that
enable a client to navigate through several levels of relationships,
such as/customers/1/orders/99/products.
However, this level of
complexity can be difficult to maintain and is inflexible if the
relationships between resources change in the future. Instead, try to
keep URIs relatively simple. Once an application has a reference to a
resource, it should be possible to use this reference to find items
related to that resource. The preceding query can be replaced with the
URI/customers/1/orders
to find all the orders for customer 1, and
then/orders/99/products
to find the products in this order.
.
Tip
Avoid requiring resource URIs more complex than
collection/item/collection
.
add a comment |
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
105
down vote
accepted
What you have done is correct. In general there can be many URIs to the same resource - there are no rules that say you shouldn't do that.
And generally, you may need to access items directly or as a subset of something else - so your structure makes sense to me.
Just because employees are accessible under department:
company/{companyid}/department/{departmentid}/employees
Doesn't mean they can't be accessible under company too:
company/{companyid}/employees
Which would return employees for that company. It depends on what is needed by your consuming client - that is what you should be designing for.
But I would hope that all URLs handlers use the same backing code to satisfy the requests so that you aren't duplicating code.
9
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
9
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.
– max
Jul 3 '16 at 5:02
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.
– kashif
Oct 2 '17 at 3:57
|
show 1 more comment
up vote
105
down vote
accepted
What you have done is correct. In general there can be many URIs to the same resource - there are no rules that say you shouldn't do that.
And generally, you may need to access items directly or as a subset of something else - so your structure makes sense to me.
Just because employees are accessible under department:
company/{companyid}/department/{departmentid}/employees
Doesn't mean they can't be accessible under company too:
company/{companyid}/employees
Which would return employees for that company. It depends on what is needed by your consuming client - that is what you should be designing for.
But I would hope that all URLs handlers use the same backing code to satisfy the requests so that you aren't duplicating code.
9
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
9
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.
– max
Jul 3 '16 at 5:02
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.
– kashif
Oct 2 '17 at 3:57
|
show 1 more comment
up vote
105
down vote
accepted
up vote
105
down vote
accepted
What you have done is correct. In general there can be many URIs to the same resource - there are no rules that say you shouldn't do that.
And generally, you may need to access items directly or as a subset of something else - so your structure makes sense to me.
Just because employees are accessible under department:
company/{companyid}/department/{departmentid}/employees
Doesn't mean they can't be accessible under company too:
company/{companyid}/employees
Which would return employees for that company. It depends on what is needed by your consuming client - that is what you should be designing for.
But I would hope that all URLs handlers use the same backing code to satisfy the requests so that you aren't duplicating code.
What you have done is correct. In general there can be many URIs to the same resource - there are no rules that say you shouldn't do that.
And generally, you may need to access items directly or as a subset of something else - so your structure makes sense to me.
Just because employees are accessible under department:
company/{companyid}/department/{departmentid}/employees
Doesn't mean they can't be accessible under company too:
company/{companyid}/employees
Which would return employees for that company. It depends on what is needed by your consuming client - that is what you should be designing for.
But I would hope that all URLs handlers use the same backing code to satisfy the requests so that you aren't duplicating code.
edited Aug 18 '16 at 14:21
Joakim
4,93773341
4,93773341
answered Oct 15 '14 at 17:11
jeremyh
4,27931717
4,27931717
9
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
9
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.
– max
Jul 3 '16 at 5:02
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.
– kashif
Oct 2 '17 at 3:57
|
show 1 more comment
9
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
9
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.
– max
Jul 3 '16 at 5:02
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.
– kashif
Oct 2 '17 at 3:57
9
9
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
This is pointing out the spirit of RESTful, there are no rules that say you should or should not do if only you consider a meaningful resource first. But further, I wonder what's the best practice for not duplicating code in such scenarios.
– abookyun
May 13 '15 at 3:18
9
9
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
@abookyun if you need both routes, then repeated controller code between them can be abstracted to service objects.
– bgcode
Dec 3 '15 at 20:37
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
This has nothing to do with REST. REST does not care about how you structure the path part of your URLs... all it cares about is valid, hopefully durable URIs...
– redben
Apr 5 '16 at 14:51
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (
/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.– max
Jul 3 '16 at 5:02
Driving at this answer, I think any api where the dynamic segments are all unique identifiers shouldn't need to handle multiple dynamic segments (
/company/3/department/2/employees/1
). If the api provides ways to get each resource, then making each of those requests could be done in either a client side library or as a one-off endpoint that reuses code.– max
Jul 3 '16 at 5:02
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example
/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.– kashif
Oct 2 '17 at 3:57
While there is no prohibition, I consider it more elegant to have only one path to a resource - keeps all mental models simpler. I also prefer that URIs don't change their resource type if there is any nesting. for example
/company/*
should only return the company resource and not change resource type at all. None of this is specified by REST - its generally a poorly specified - just personal preference.– kashif
Oct 2 '17 at 3:57
|
show 1 more comment
up vote
103
down vote
I've tried both design strategies - nested and non-nested endpoints. I've found that:
if the nested resource has a primary key and you don't have its parent primary key, the nested structure requires you to get it, even though the system doesn't actually require it.
nested endpoints typically require redundant endpoints. In other words, you will more often than not, need the additional /employees endpoint so you can get a list of employees across departments. If you have /employees, what exactly does /companies/departments/employees buy you?
nesting endpoints don't evolve as nicely. E.g. you might not need to search for employees now but you might later and if you have a nested structure, you have no choice but to add another endpoint. With a non-nested design, you just add more parameters, which is simpler.
sometimes a resource could have multiple types of parents. Resulting in multiple endpoints all returning the same resource.
redundant endpoints makes the docs harder to write and also makes the api harder to learn.
In short, the non-nested design seems to allow a more flexible and simpler endpoint schema.
11
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
3
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
3
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
1
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
add a comment |
up vote
103
down vote
I've tried both design strategies - nested and non-nested endpoints. I've found that:
if the nested resource has a primary key and you don't have its parent primary key, the nested structure requires you to get it, even though the system doesn't actually require it.
nested endpoints typically require redundant endpoints. In other words, you will more often than not, need the additional /employees endpoint so you can get a list of employees across departments. If you have /employees, what exactly does /companies/departments/employees buy you?
nesting endpoints don't evolve as nicely. E.g. you might not need to search for employees now but you might later and if you have a nested structure, you have no choice but to add another endpoint. With a non-nested design, you just add more parameters, which is simpler.
sometimes a resource could have multiple types of parents. Resulting in multiple endpoints all returning the same resource.
redundant endpoints makes the docs harder to write and also makes the api harder to learn.
In short, the non-nested design seems to allow a more flexible and simpler endpoint schema.
11
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
3
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
3
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
1
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
add a comment |
up vote
103
down vote
up vote
103
down vote
I've tried both design strategies - nested and non-nested endpoints. I've found that:
if the nested resource has a primary key and you don't have its parent primary key, the nested structure requires you to get it, even though the system doesn't actually require it.
nested endpoints typically require redundant endpoints. In other words, you will more often than not, need the additional /employees endpoint so you can get a list of employees across departments. If you have /employees, what exactly does /companies/departments/employees buy you?
nesting endpoints don't evolve as nicely. E.g. you might not need to search for employees now but you might later and if you have a nested structure, you have no choice but to add another endpoint. With a non-nested design, you just add more parameters, which is simpler.
sometimes a resource could have multiple types of parents. Resulting in multiple endpoints all returning the same resource.
redundant endpoints makes the docs harder to write and also makes the api harder to learn.
In short, the non-nested design seems to allow a more flexible and simpler endpoint schema.
I've tried both design strategies - nested and non-nested endpoints. I've found that:
if the nested resource has a primary key and you don't have its parent primary key, the nested structure requires you to get it, even though the system doesn't actually require it.
nested endpoints typically require redundant endpoints. In other words, you will more often than not, need the additional /employees endpoint so you can get a list of employees across departments. If you have /employees, what exactly does /companies/departments/employees buy you?
nesting endpoints don't evolve as nicely. E.g. you might not need to search for employees now but you might later and if you have a nested structure, you have no choice but to add another endpoint. With a non-nested design, you just add more parameters, which is simpler.
sometimes a resource could have multiple types of parents. Resulting in multiple endpoints all returning the same resource.
redundant endpoints makes the docs harder to write and also makes the api harder to learn.
In short, the non-nested design seems to allow a more flexible and simpler endpoint schema.
answered Apr 4 '16 at 19:01
Patc
1,047142
1,047142
11
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
3
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
3
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
1
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
add a comment |
11
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
3
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
3
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
1
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
11
11
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Was very refreshing to come across this answer. I have been using nested endpoints for several months now after being taught that was the "right way". I came to all of the same conclusions you listed above. So much easier with a non-nested design.
– user3344977
Apr 20 '17 at 16:16
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
Would it also mean that primary key should be delivered a parameter of a query string instead of being delivered as a part of main url. /Employees?id=500, instead of /Employees/500. Wouldn't that also scale better in case you also require a primary key from a parent resource?
– mko
Nov 6 '17 at 12:32
3
3
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
You seem to list some of the downsides as upsides. "Just cram more parameters into a single end-point" makes the API harder to document and learn, not the other way around. ;-)
– Drenmi
Nov 21 '17 at 17:21
3
3
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
Not a fan of this answer. There's no need to introduce redundant endpoints just because you've added a nested resource. It's also not a problem to have the same resource returned by multiple parents, provided those parents genuinely own the nested resource. It's not a problem to get a parent resource to learn how to interact with the nested resources. A good discoverable REST API should do this.
– Scottm
Dec 11 '17 at 9:27
1
1
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
@Scottm - One drawback of nested resources that I came across is that it could lead to returning incorrect data if the parent resource ids are incorrect/mismatch. Assuming there are no authorization issues, it is left upto the api implementation to verify that the nested resource is indeed a child of the parent resource that is passed. If this check is not coded for, the api response could be incorrect leading to corruption. What are your thoughts?
– Andy Dufresne
Jul 12 at 14:40
add a comment |
up vote
53
down vote
I've moved what I've done from the question to an answer where more people are likely to see it.
What I've done is to have the creation endpoints at the nested endpoint, The canonical endpoint for modifying or querying an item is not at the nested resource.
So in this example (just listing the endpoints that change a resource)
POST
/companies/
creates a new company returns a link to the created company.
POST
/companies/{companyId}/departments
when a department is put creates the new department returns a link to/departments/{departmentId}
PUT
/departments/{departmentId}
modifies a department
POST
/departments/{deparmentId}/employees
creates a new employee returns a link to/employees/{employeeId}
So there are root level resources for each of the collections. However the create is in the owning object.
2
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I guess you usedPOST
meaningPUT
, and otherwise.
– Gerardo Lima
Jan 18 at 15:43
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
|
show 4 more comments
up vote
53
down vote
I've moved what I've done from the question to an answer where more people are likely to see it.
What I've done is to have the creation endpoints at the nested endpoint, The canonical endpoint for modifying or querying an item is not at the nested resource.
So in this example (just listing the endpoints that change a resource)
POST
/companies/
creates a new company returns a link to the created company.
POST
/companies/{companyId}/departments
when a department is put creates the new department returns a link to/departments/{departmentId}
PUT
/departments/{departmentId}
modifies a department
POST
/departments/{deparmentId}/employees
creates a new employee returns a link to/employees/{employeeId}
So there are root level resources for each of the collections. However the create is in the owning object.
2
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I guess you usedPOST
meaningPUT
, and otherwise.
– Gerardo Lima
Jan 18 at 15:43
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
|
show 4 more comments
up vote
53
down vote
up vote
53
down vote
I've moved what I've done from the question to an answer where more people are likely to see it.
What I've done is to have the creation endpoints at the nested endpoint, The canonical endpoint for modifying or querying an item is not at the nested resource.
So in this example (just listing the endpoints that change a resource)
POST
/companies/
creates a new company returns a link to the created company.
POST
/companies/{companyId}/departments
when a department is put creates the new department returns a link to/departments/{departmentId}
PUT
/departments/{departmentId}
modifies a department
POST
/departments/{deparmentId}/employees
creates a new employee returns a link to/employees/{employeeId}
So there are root level resources for each of the collections. However the create is in the owning object.
I've moved what I've done from the question to an answer where more people are likely to see it.
What I've done is to have the creation endpoints at the nested endpoint, The canonical endpoint for modifying or querying an item is not at the nested resource.
So in this example (just listing the endpoints that change a resource)
POST
/companies/
creates a new company returns a link to the created company.
POST
/companies/{companyId}/departments
when a department is put creates the new department returns a link to/departments/{departmentId}
PUT
/departments/{departmentId}
modifies a department
POST
/departments/{deparmentId}/employees
creates a new employee returns a link to/employees/{employeeId}
So there are root level resources for each of the collections. However the create is in the owning object.
edited Aug 29 at 12:11
answered Sep 28 '15 at 10:27
Wes
2,48422350
2,48422350
2
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I guess you usedPOST
meaningPUT
, and otherwise.
– Gerardo Lima
Jan 18 at 15:43
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
|
show 4 more comments
2
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I guess you usedPOST
meaningPUT
, and otherwise.
– Gerardo Lima
Jan 18 at 15:43
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
2
2
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I have come up with the same type of design as well. I think it's intuitive to create things like this "where they belong", but then still be able to list them globally. Even more so when there's a relationship where a resource MUST have a parent. Then creating that resource globally does not make that obvious, but doing it in a sub-resource like this makes perfect sense.
– Joakim
Sep 11 '16 at 20:27
I guess you used
POST
meaning PUT
, and otherwise.– Gerardo Lima
Jan 18 at 15:43
I guess you used
POST
meaning PUT
, and otherwise.– Gerardo Lima
Jan 18 at 15:43
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
Actually no Note that I'm not using pre assigned Ids for creation as the server in this case is responsible for returning the id (in the link). Therefore writing POST is correct (can't do a get on the same implementation). The put however changes the entire resource but its still available at the same location so I PUT it. PUT vs POST is a different matter and is controversial too. For example stackoverflow.com/questions/630453/put-vs-post-in-rest
– Wes
Jan 18 at 16:57
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Wes Even I prefer modifying verb methods to be under the parent. But, do you see passing query parameter for global resource is accepted well? Ex : POST /departments with query parameter company=company-id
– Ayyappa
Apr 9 at 12:48
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
@Ayyappa Its not something I would personally do, but I woudn't be too shocked if it did happen. Normally I don't like mixing query strings with posted bodies. But I have done it in the past many years ago.
– Wes
Apr 11 at 8:03
|
show 4 more comments
up vote
6
down vote
I disagree with this kind of path
GET /companies/{companyId}/departments
If you want to get departments, I think it's better to use a /departments resource
GET /departments?companyId=123
I suppose you have a companies
table and a departments
table then classes to map them in the programming language you use. I also assume that departments could be attached to other entities than companies, so a /departments resource is straightforward, it's convenient to have resources mapped to tables and also you don't need as many endpoints since you can reuse
GET /departments?companyId=123
for any kind of search, for instance
GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.
If you want to create a department, the
POST /departments
resource should be used and the request body should contain the company ID (if the department can be linked to only one company).
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
2
It may also make sense to allow departments to be included via lazy loading when fetching a company, egGET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.
– Matthew Daly
Jul 27 '17 at 11:31
When you're setting up acls you probably want to restrict the/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`
– Cuzox
Dec 26 '17 at 13:34
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
add a comment |
up vote
6
down vote
I disagree with this kind of path
GET /companies/{companyId}/departments
If you want to get departments, I think it's better to use a /departments resource
GET /departments?companyId=123
I suppose you have a companies
table and a departments
table then classes to map them in the programming language you use. I also assume that departments could be attached to other entities than companies, so a /departments resource is straightforward, it's convenient to have resources mapped to tables and also you don't need as many endpoints since you can reuse
GET /departments?companyId=123
for any kind of search, for instance
GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.
If you want to create a department, the
POST /departments
resource should be used and the request body should contain the company ID (if the department can be linked to only one company).
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
2
It may also make sense to allow departments to be included via lazy loading when fetching a company, egGET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.
– Matthew Daly
Jul 27 '17 at 11:31
When you're setting up acls you probably want to restrict the/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`
– Cuzox
Dec 26 '17 at 13:34
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
add a comment |
up vote
6
down vote
up vote
6
down vote
I disagree with this kind of path
GET /companies/{companyId}/departments
If you want to get departments, I think it's better to use a /departments resource
GET /departments?companyId=123
I suppose you have a companies
table and a departments
table then classes to map them in the programming language you use. I also assume that departments could be attached to other entities than companies, so a /departments resource is straightforward, it's convenient to have resources mapped to tables and also you don't need as many endpoints since you can reuse
GET /departments?companyId=123
for any kind of search, for instance
GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.
If you want to create a department, the
POST /departments
resource should be used and the request body should contain the company ID (if the department can be linked to only one company).
I disagree with this kind of path
GET /companies/{companyId}/departments
If you want to get departments, I think it's better to use a /departments resource
GET /departments?companyId=123
I suppose you have a companies
table and a departments
table then classes to map them in the programming language you use. I also assume that departments could be attached to other entities than companies, so a /departments resource is straightforward, it's convenient to have resources mapped to tables and also you don't need as many endpoints since you can reuse
GET /departments?companyId=123
for any kind of search, for instance
GET /departments?name=xxx
GET /departments?companyId=123&name=xxx
etc.
If you want to create a department, the
POST /departments
resource should be used and the request body should contain the company ID (if the department can be linked to only one company).
edited Feb 13 '16 at 18:54
answered Feb 13 '16 at 18:33
Maxime Laval
1,30532147
1,30532147
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
2
It may also make sense to allow departments to be included via lazy loading when fetching a company, egGET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.
– Matthew Daly
Jul 27 '17 at 11:31
When you're setting up acls you probably want to restrict the/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`
– Cuzox
Dec 26 '17 at 13:34
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
add a comment |
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
2
It may also make sense to allow departments to be included via lazy loading when fetching a company, egGET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.
– Matthew Daly
Jul 27 '17 at 11:31
When you're setting up acls you probably want to restrict the/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`
– Cuzox
Dec 26 '17 at 13:34
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
To me, this is an acceptable approach only if the nested object makes sense as an atomic object. If they are not, It wouldnt really make sense to break them apart.
– Simon Aronsson
Sep 26 '16 at 10:26
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
This is what I said, if you also want to be able to retrieve departments, meaning if you'll use a /departments endpoint.
– Maxime Laval
Sep 26 '16 at 17:21
2
2
It may also make sense to allow departments to be included via lazy loading when fetching a company, eg
GET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.– Matthew Daly
Jul 27 '17 at 11:31
It may also make sense to allow departments to be included via lazy loading when fetching a company, eg
GET /companies/{companyId}?include=departments
, since this allows both the company and its departments to be fetched in a single HTTP request. Fractal does this really well.– Matthew Daly
Jul 27 '17 at 11:31
When you're setting up acls you probably want to restrict the
/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`– Cuzox
Dec 26 '17 at 13:34
When you're setting up acls you probably want to restrict the
/departments
endpoint to only be accessible by an admin, and have each company access their own departments only through ` /companies/{companyId}/departments`– Cuzox
Dec 26 '17 at 13:34
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
@MatthewDaly OData also does that nicely with $expand
– Robert Grant
Jan 2 at 10:37
add a comment |
up vote
6
down vote
How your URLs look have nothing to do with REST. Anything goes. It actually is an "implementation detail". So just like how you name your variables. All they have to be is unique and durable.
Don't waste too much time on this, just make a choice and stick to it/be consistent. For example if you go with hierarchies then you do it for all your resources. If you go with query parameters...etc just like naming conventions in your code.
Why so ? As far as I know a "RESTful" API is to be browsable (you know..."Hypermedia as the Engine of Application State"), therefore an API client does not care about what your URLs are like as long as they're valid (there's no SEO, no human that needs to read those "friendly urls", except may be for debugging...)
How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be.
The most important thing is that your API client know how to interpret your media type.
For example it knows that :
- your media type has a links property that lists available/related links.
- Each link is identified by a relationship (just like browsers know that link[rel="stylesheet"] means its a style sheet or rel=favico is a link to a favicon...)
- and it knowns what those relationships mean ("companies" mean a list of companies,"search" means a templated url for doing a search on a list of resource, "departments" means departments of the current resource )
Below is an example HTTP exchange (bodies are in yaml since it's easier to write):
Request
GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml
Response: a list of links to main resource (companies, people, whatever...)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: this is your API's entrypoint (like a homepage)
links:
# could be some random path https://api.acme.local/modskmklmkdsml
# the only thing the API client cares about is the key (or rel) "companies"
companies: https://api.acme.local/companies
people: https://api.acme.local/people
Request: link to companies (using previous response's body.links.companies)
GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml
Response: a partial list of companies (under items), the resource contains related links, like link to get the next couple of companies (body.links.next) an other (templated) link to search (body.links.search)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: representation of a list of companies
links:
# link to the next page
next: https://api.acme.local/companies?page=2
# templated link for search
search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
add:
href: https://api.acme.local/companies
method: POST
items:
- name: company1
links:
self: https://api.acme.local/companies/8er13eo
# and here is the link to departments
# again the client only cares about the key department
department: https://api.acme.local/companies/8er13eo/departments
- name: company2
links:
self: https://api.acme.local/companies/9r13d4l
# or could be in some other location !
department: https://api2.acme.local/departments?company=8er13eo
So as you see if you go the links/relations way how you structure the path part of your URLs does't have any value to your API client. And if your are communicating the structure of your URLs to your client as documentation, then your are not doing REST (or at least not Level 3 as per "Richardson's maturity model")
6
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
1
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
3
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
add a comment |
up vote
6
down vote
How your URLs look have nothing to do with REST. Anything goes. It actually is an "implementation detail". So just like how you name your variables. All they have to be is unique and durable.
Don't waste too much time on this, just make a choice and stick to it/be consistent. For example if you go with hierarchies then you do it for all your resources. If you go with query parameters...etc just like naming conventions in your code.
Why so ? As far as I know a "RESTful" API is to be browsable (you know..."Hypermedia as the Engine of Application State"), therefore an API client does not care about what your URLs are like as long as they're valid (there's no SEO, no human that needs to read those "friendly urls", except may be for debugging...)
How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be.
The most important thing is that your API client know how to interpret your media type.
For example it knows that :
- your media type has a links property that lists available/related links.
- Each link is identified by a relationship (just like browsers know that link[rel="stylesheet"] means its a style sheet or rel=favico is a link to a favicon...)
- and it knowns what those relationships mean ("companies" mean a list of companies,"search" means a templated url for doing a search on a list of resource, "departments" means departments of the current resource )
Below is an example HTTP exchange (bodies are in yaml since it's easier to write):
Request
GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml
Response: a list of links to main resource (companies, people, whatever...)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: this is your API's entrypoint (like a homepage)
links:
# could be some random path https://api.acme.local/modskmklmkdsml
# the only thing the API client cares about is the key (or rel) "companies"
companies: https://api.acme.local/companies
people: https://api.acme.local/people
Request: link to companies (using previous response's body.links.companies)
GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml
Response: a partial list of companies (under items), the resource contains related links, like link to get the next couple of companies (body.links.next) an other (templated) link to search (body.links.search)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: representation of a list of companies
links:
# link to the next page
next: https://api.acme.local/companies?page=2
# templated link for search
search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
add:
href: https://api.acme.local/companies
method: POST
items:
- name: company1
links:
self: https://api.acme.local/companies/8er13eo
# and here is the link to departments
# again the client only cares about the key department
department: https://api.acme.local/companies/8er13eo/departments
- name: company2
links:
self: https://api.acme.local/companies/9r13d4l
# or could be in some other location !
department: https://api2.acme.local/departments?company=8er13eo
So as you see if you go the links/relations way how you structure the path part of your URLs does't have any value to your API client. And if your are communicating the structure of your URLs to your client as documentation, then your are not doing REST (or at least not Level 3 as per "Richardson's maturity model")
6
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
1
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
3
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
add a comment |
up vote
6
down vote
up vote
6
down vote
How your URLs look have nothing to do with REST. Anything goes. It actually is an "implementation detail". So just like how you name your variables. All they have to be is unique and durable.
Don't waste too much time on this, just make a choice and stick to it/be consistent. For example if you go with hierarchies then you do it for all your resources. If you go with query parameters...etc just like naming conventions in your code.
Why so ? As far as I know a "RESTful" API is to be browsable (you know..."Hypermedia as the Engine of Application State"), therefore an API client does not care about what your URLs are like as long as they're valid (there's no SEO, no human that needs to read those "friendly urls", except may be for debugging...)
How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be.
The most important thing is that your API client know how to interpret your media type.
For example it knows that :
- your media type has a links property that lists available/related links.
- Each link is identified by a relationship (just like browsers know that link[rel="stylesheet"] means its a style sheet or rel=favico is a link to a favicon...)
- and it knowns what those relationships mean ("companies" mean a list of companies,"search" means a templated url for doing a search on a list of resource, "departments" means departments of the current resource )
Below is an example HTTP exchange (bodies are in yaml since it's easier to write):
Request
GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml
Response: a list of links to main resource (companies, people, whatever...)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: this is your API's entrypoint (like a homepage)
links:
# could be some random path https://api.acme.local/modskmklmkdsml
# the only thing the API client cares about is the key (or rel) "companies"
companies: https://api.acme.local/companies
people: https://api.acme.local/people
Request: link to companies (using previous response's body.links.companies)
GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml
Response: a partial list of companies (under items), the resource contains related links, like link to get the next couple of companies (body.links.next) an other (templated) link to search (body.links.search)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: representation of a list of companies
links:
# link to the next page
next: https://api.acme.local/companies?page=2
# templated link for search
search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
add:
href: https://api.acme.local/companies
method: POST
items:
- name: company1
links:
self: https://api.acme.local/companies/8er13eo
# and here is the link to departments
# again the client only cares about the key department
department: https://api.acme.local/companies/8er13eo/departments
- name: company2
links:
self: https://api.acme.local/companies/9r13d4l
# or could be in some other location !
department: https://api2.acme.local/departments?company=8er13eo
So as you see if you go the links/relations way how you structure the path part of your URLs does't have any value to your API client. And if your are communicating the structure of your URLs to your client as documentation, then your are not doing REST (or at least not Level 3 as per "Richardson's maturity model")
How your URLs look have nothing to do with REST. Anything goes. It actually is an "implementation detail". So just like how you name your variables. All they have to be is unique and durable.
Don't waste too much time on this, just make a choice and stick to it/be consistent. For example if you go with hierarchies then you do it for all your resources. If you go with query parameters...etc just like naming conventions in your code.
Why so ? As far as I know a "RESTful" API is to be browsable (you know..."Hypermedia as the Engine of Application State"), therefore an API client does not care about what your URLs are like as long as they're valid (there's no SEO, no human that needs to read those "friendly urls", except may be for debugging...)
How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be.
The most important thing is that your API client know how to interpret your media type.
For example it knows that :
- your media type has a links property that lists available/related links.
- Each link is identified by a relationship (just like browsers know that link[rel="stylesheet"] means its a style sheet or rel=favico is a link to a favicon...)
- and it knowns what those relationships mean ("companies" mean a list of companies,"search" means a templated url for doing a search on a list of resource, "departments" means departments of the current resource )
Below is an example HTTP exchange (bodies are in yaml since it's easier to write):
Request
GET / HTTP/1.1
Host: api.acme.io
Accept: text/yaml, text/acme-mediatype+yaml
Response: a list of links to main resource (companies, people, whatever...)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:04:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: this is your API's entrypoint (like a homepage)
links:
# could be some random path https://api.acme.local/modskmklmkdsml
# the only thing the API client cares about is the key (or rel) "companies"
companies: https://api.acme.local/companies
people: https://api.acme.local/people
Request: link to companies (using previous response's body.links.companies)
GET /companies HTTP/1.1
Host: api.acme.local
Accept: text/yaml, text/acme-mediatype+yaml
Response: a partial list of companies (under items), the resource contains related links, like link to get the next couple of companies (body.links.next) an other (templated) link to search (body.links.search)
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 15:06:00 GMT
Last-Modified: Tue, 05 Apr 2016 00:00:00 GMT
Content-Type: text/acme-mediatype+yaml
# body: representation of a list of companies
links:
# link to the next page
next: https://api.acme.local/companies?page=2
# templated link for search
search: https://api.acme.local/companies?query={query}
# you could provide available actions related to this resource
actions:
add:
href: https://api.acme.local/companies
method: POST
items:
- name: company1
links:
self: https://api.acme.local/companies/8er13eo
# and here is the link to departments
# again the client only cares about the key department
department: https://api.acme.local/companies/8er13eo/departments
- name: company2
links:
self: https://api.acme.local/companies/9r13d4l
# or could be in some other location !
department: https://api2.acme.local/departments?company=8er13eo
So as you see if you go the links/relations way how you structure the path part of your URLs does't have any value to your API client. And if your are communicating the structure of your URLs to your client as documentation, then your are not doing REST (or at least not Level 3 as per "Richardson's maturity model")
edited Aug 26 '16 at 16:11
answered Apr 5 '16 at 14:49
redben
3,79843559
3,79843559
6
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
1
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
3
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
add a comment |
6
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
1
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
3
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
6
6
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
"How nice/understandable a URL is in a REST API is only interesting to you as the API developer, not the API client, as would the name of a variable in your code be." Why would this NOT be interesting? This is very important, if anyone but yourself is also using the API. This is part of the user experience, so I would say it is very important that this is easy to understand for the API client developers. Making things even more easy to understand by linking resources clearly is of course a bonus (level 3 in the url you provide). Everything should be intuitive and logical with clear relations.
– Joakim
Sep 11 '16 at 20:33
1
1
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
@Joakim If you are making a level 3 rest API (Hypertext As The Engine Of Application State), then the url's path structure is absolutely of no interest to the client (as long as it is valid). If you are not aiming for level 3, then yes, it is important and should be guessable. But real REST is level 3. A good article: martinfowler.com/articles/richardsonMaturityModel.html
– redben
Sep 11 '16 at 21:19
3
3
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
I object to ever creating an API or UI that is not user friendly for human beings. Level 3 or not, I agree linking resources is a great idea. But to suggest doing so "makes it possible to change URL scheme" is to be out of touch with reality, and how people use APIs. So it's a bad recommendation. But sure in the best of all worlds everyone would be at Level 3 REST. I incorporate hyperlinks AND use a humanly understandable URL scheme. Level 3 does not exclude the former, and one SHOULD care in my opinion. Good article though :)
– Joakim
Sep 11 '16 at 21:29
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
One should of course care for the sake of maintainability and other concerns, I think you miss the point of my answer : the way the url looks does not deserve a lot of thinking and you should "just make a choice and stick to it/be consistent" as I said in the answer. And in the case of a REST API, at least my opinion, user friendlyness is not in the url, it is mostly in (the media type) Anyway I hope you understand my point :)
– redben
Sep 11 '16 at 22:14
add a comment |
up vote
5
down vote
I've read all of above answer but seem like have no common strategy. I found a good article about best practices in Design API from Microsoft Documents. I think you should refer.
In more complex systems, it can be tempting to provide URIs that
enable a client to navigate through several levels of relationships,
such as/customers/1/orders/99/products.
However, this level of
complexity can be difficult to maintain and is inflexible if the
relationships between resources change in the future. Instead, try to
keep URIs relatively simple. Once an application has a reference to a
resource, it should be possible to use this reference to find items
related to that resource. The preceding query can be replaced with the
URI/customers/1/orders
to find all the orders for customer 1, and
then/orders/99/products
to find the products in this order.
.
Tip
Avoid requiring resource URIs more complex than
collection/item/collection
.
add a comment |
up vote
5
down vote
I've read all of above answer but seem like have no common strategy. I found a good article about best practices in Design API from Microsoft Documents. I think you should refer.
In more complex systems, it can be tempting to provide URIs that
enable a client to navigate through several levels of relationships,
such as/customers/1/orders/99/products.
However, this level of
complexity can be difficult to maintain and is inflexible if the
relationships between resources change in the future. Instead, try to
keep URIs relatively simple. Once an application has a reference to a
resource, it should be possible to use this reference to find items
related to that resource. The preceding query can be replaced with the
URI/customers/1/orders
to find all the orders for customer 1, and
then/orders/99/products
to find the products in this order.
.
Tip
Avoid requiring resource URIs more complex than
collection/item/collection
.
add a comment |
up vote
5
down vote
up vote
5
down vote
I've read all of above answer but seem like have no common strategy. I found a good article about best practices in Design API from Microsoft Documents. I think you should refer.
In more complex systems, it can be tempting to provide URIs that
enable a client to navigate through several levels of relationships,
such as/customers/1/orders/99/products.
However, this level of
complexity can be difficult to maintain and is inflexible if the
relationships between resources change in the future. Instead, try to
keep URIs relatively simple. Once an application has a reference to a
resource, it should be possible to use this reference to find items
related to that resource. The preceding query can be replaced with the
URI/customers/1/orders
to find all the orders for customer 1, and
then/orders/99/products
to find the products in this order.
.
Tip
Avoid requiring resource URIs more complex than
collection/item/collection
.
I've read all of above answer but seem like have no common strategy. I found a good article about best practices in Design API from Microsoft Documents. I think you should refer.
In more complex systems, it can be tempting to provide URIs that
enable a client to navigate through several levels of relationships,
such as/customers/1/orders/99/products.
However, this level of
complexity can be difficult to maintain and is inflexible if the
relationships between resources change in the future. Instead, try to
keep URIs relatively simple. Once an application has a reference to a
resource, it should be possible to use this reference to find items
related to that resource. The preceding query can be replaced with the
URI/customers/1/orders
to find all the orders for customer 1, and
then/orders/99/products
to find the products in this order.
.
Tip
Avoid requiring resource URIs more complex than
collection/item/collection
.
edited Jun 19 at 2:25
answered Jun 19 at 2:15
Long Nguyen
1,31211322
1,31211322
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f20951419%2fwhat-are-best-practices-for-rest-nested-resources%23new-answer', 'question_page');
}
);
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
1
This is almost exactly the oppsite problem to that described in stackoverflow.com/questions/7104578/… though the answers may be related. Both questions are about ownership but that example implies that the top level object isn't the owning one.
– Wes
Jan 6 '14 at 13:55
1
Exactly what I was wondering about. For the given use case your solution seems fine, but what if the relation is an aggregation rather than a composition? Still struggling to figure out what the best practice is here... Also, does this solution imply only the creation of the relationship, e.g. an existing person is employed or does it create a person object?
– Jakob O.
Mar 28 '14 at 10:32
It creates a person in my fictitious example. The reason I used those domain terms is its a reasonably understandable example, though mimicking my actual problem. Have you looked through the linked question that may halp you more for an aggragation relationship.
– Wes
Apr 8 '14 at 13:05
I've split my question into an answer and a question.
– Wes
Sep 28 '15 at 10:30
I'm voting to close this question as off-topic because its about a pattern rather than a programming problem and has gathered too many votes.
– Wes
Oct 26 '17 at 23:15