29

My question is about the advantages of nesting resources when building URLs for API purposes. Consider the following two alternatives for accessing an employee resource:

/api/employees?department=1   # flat

Vs.

/api/departments/1/employees  # nested

Now consider the task of developing a general purpose library to access REST resources from an API. If all routes were flat, such a REST wrapper library would only need to know the name of the resource being accessed:

store.query('employees', {department_id:1})   =>   /api/employees?department=1

However, if we were to support nested routes, this wrapper would need to know extra information about what models are nested and under which other resource, in order to know how to build the URLs for referencing such a model. Given that not all models would be nested under the same parent resource, and even some models would not be nested at all, the REST wrapper library would need to have some sort of configuration describing all this extra knowledge that wouldn't be needed otherwise.

So my questions are:

  • Are there any real advantages to nested resource routes in an API? (Which is not meant to be consumed by end users, and therefore gains less from having prettier URLs).

  • Is the nested approach really better than flat, beyond aesthetics, so as to justify the extra effort and complexity introduced to support the lack of uniformity in resource URL building?

See also: https://stackoverflow.com/a/36410780/621809

UPDATE: IMPORTANT CLARIFICATION

I realize from some of the comments and answers, that I wasn't clear enough regarding one aspect: I'm not against addressing single resources with URLs like /employees/5 or /departments/1. I don't consider that to be nested.

When I say nested resources, I refer to URLs like /departments/1/employees where a resource is addressed always within the context of another resource. The main issue is the fact that for URL building, a generic library would need to know extra stuff like "employees are nested under departments" but "branches are not nested under anything". If all resources could be addressed RESTfully, but in a flat fashion, it is simpler and more predictable to know how to address them.

When you think about it, in databases you don't need to know extra information in order to know how to address a collection of objects (e.g. a table in a RDMS). You always refer to the collection of employees as employees, not as departments/5/employees.

Community
  • 1
  • 1
Ernesto
  • 3,837
  • 6
  • 35
  • 56
  • I think of REST APIs as a way to access resources, and that way to access the resources should be as easy as possible. Pick which ever makes more sense for your application. I prefer the first option you listed, as it makes the most sense (and common). I'd use nested REST API URLs to drill-down on resources (i.e. /employees/{uid} or /departments/{uid}. There seems to be a bi-directional relationship between dpts. and employees, maybe also have an API that exposes dpts -> employee fetching. i.e. /departments?user.name=Ernesto. Of course, it all depends on how you are structuring the backend – Lucas Crawford Aug 27 '16 at 04:32
  • Lucas Crawford: see my clarification above regarding URLs like `/employees/{uid}`. Those are not the ones I'm concerned about, because those do not fall under the definition of nested resources. – Ernesto Aug 27 '16 at 10:43
  • 1
    A URI as a whole is a pointer to some resource, including any path, matrix or query parameters. You might think of the URI as a key used by (intermediary) caches to determine whether a representation is available for that key or not. By itself, a URI does not convey any parent-child relationship. So a URI like `/api/companies/123/users/456` does not necessarily state that users is a subresource of companies. You might design your system however to exactly do this, but a client shouldn't rely on such a knowledge! Instead use link relations to hint clinets about the semantical context – Roman Vottner Apr 15 '19 at 09:25

4 Answers4

6

What happens if you want do drill down a couple more levels?

/api/addresses?departmentId=1&employeeId=2&addressId=3

vs

/api/departments/1/employees/2/addresses/3

The Address endpoint suddenly becames bloated with parameters.

Also, if you're looking at the Richardson Maturity Model level 3, RESTful APIs are meant to be discoverable through links. For example, from the top level, say /api/version(/1), you would discover there's a link to the departments. Here's how this could look in a tool like HAL Browser:

"api:department-query": {
  "href": "http://apiname:port/api/departments?pageNumber={pageNumber}&pageSize={pageSize}&sort={sort}"
},
"api:department-by-id": {
  "href": "http://apiname:port/api/departments?departmentId={departmentId}"
}

(either a query that might list them all, in a paged manner eventually, or a parameterized link that would go directly to a specific department, provided you know the id).

The advantage here would be that the client would only need to know the relationship (link) name, while the server would be mostly free to alter the relationship (and resource) url.

Alexandru Marculescu
  • 5,569
  • 6
  • 34
  • 50
  • 7
    Thanks for your response. Just a follow up: what is exactly wrong with the flat version being "bloated with parameters"? Besides the use of the word "bloated", the fact that it has query string params is bad because...? In the end I think all objections boil down to "flat approach leads to uglier URLs". I'm trying to figure out if there's something beyond aesthetics. – Ernesto Aug 27 '16 at 07:41
  • 4
    And BTW, I think that even nested-approach proponents warn against too deep nesting like the example you put. Isn't it? – Ernesto Aug 27 '16 at 07:43
  • it's not about uglier URLs, which doesn't matter too much really, but what about inside your code? and it's also about exposing what is needed by the clients for your use cases, [nothing more, nothing less](https://www.infoq.com/articles/rest-api-on-cqrs); the first scenario also hase a more "SOAP" feel to it - just call method x (aka "departments"/"addresses") with y parameters, depending what you want (addresses for the whole department? employeeId is optional then) – Alexandru Marculescu Aug 27 '16 at 07:52
  • The main difference between SOAP and REST is that in SOAP URLs represented actions that one was executing when requesting them. Whereas in REST URLs must represent resources, that is nouns. I don't see how the flat version fails at addressing a noun. You would still do things like `POST /employees` to create a new role, and `GET /employees?department_id=5` instead of `/departments/5/employees` to retrieve the collection of employees on that department. – Ernesto Aug 27 '16 at 10:46
  • However, nice point about the json responses including links to the associated data. We have been considering that, as I think it's the only alternative under which going nested makes sense. As you can see, my main concern is predictability on how to address resources. If base resources would include in their response information about how to address sub-resources, then fine. A client library would not then be concerned with URL building. We probably will go down that road. – Ernesto Aug 27 '16 at 10:57
  • 7
    Also, after having read your answer in more detail, your example of `/api/departments/1/employees/2/addresses/3` would really be `/addresses/3` in my flat scheme. Not `/api/addresses?departmentId=1&employeeId=2&addressId=3` like you suggested. That's precisely my point. That you don't need the extra IDs to address the nested resource. – Ernesto Aug 27 '16 at 18:10
  • 1
    One biggest drawback of nested resources 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. – Andy Dufresne Jul 12 '18 at 14:32
4

Old post, but not satisfactory answer for me.

It depends on your API. If your data is hierarchical and do not need to access resources without filtering them by their parents, then nested is OK (and not nested too).

If your ids are long (GUIDs), your hierarchy is deep, or you need to access any resource without filtering by its parents then not nested is a good option.

Try to have a unified interface and not having many ways for accessing the same resource.

Try this link that explains this a lot better: https://www.moesif.com/blog/technical/api-design/REST-API-Design-Best-Practices-for-Sub-and-Nested-Resources/

Dodger
  • 342
  • 3
  • 9
0

From my experience: Q1. Easier to use, hard to implement because of relational model Q2. Nested is better when it comes to permissions and others potential checks that you can do before you go levels down

Serge Semenov
  • 9,232
  • 3
  • 23
  • 24
  • 1
    Thanks for your feedback. Could you elaborate on what checks can you make on the nested versions that you cannot do if going with the flat approach? – Ernesto Aug 27 '16 at 07:42
0

I'd vote for 2'nd solution, based on model and security.

The department is in the path and does not have to be in the payload, neither for read- or write.

IF depatment of employee is to be changed, the depID could be included in the payload or through separate endpoint (with separate grant) /employees/{ID}.

Teson
  • 6,644
  • 8
  • 46
  • 69