Live data from Hacker News

Ask HN: Nested Resources in REST/HTTP API URLs?

news.ycombinator.com

21–30 of 72 posts

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#21
post #15
post #4

In case the organisation is basically a tenant in multi-tenant application I would leave it out of the API and resolve it in another way, but if it is not I would leave it in. Does that make sense?

In some cases there might be a next stage of complexity where you have users with access to multiple tenants who are browsing them in different tabs. Then putting the organization as the top level in _every_ URL helps signal intent; otherwise you have to take other precautions that someone isn't on a tab with Organization A, clicks "Post new article" button (-> POST /articles) and happens to have their session logged…

(edit, see mnutt's reply)

I'd really recommend putting the organization name in the content of the page in that example. Users don't really look at URLs, browsers de-prioritize them and often only display part of the URL.

Also, depending on front-end implementation the REST API URL may not be displayed in the URL bar. A single page app may use example.com/#create-article for posting an article. A mobile app wouldn't even have a URL bar.

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#22
> /organizations/:organizationId/blogs/:blogId OR /blogs/:blogId (and get the organization from somewhere else like an auth token)

You make it sound like the blog posts are keyed by (organizationId, blogId). If this is so, then /organizations/:organizationId/blogs/:blogId is clearly superior. But if blogId alone is sufficient to identify the blog post, then /blogs/:blogId is very likely to be wiser.

But you also make it sound like sessions might be scoped to an organization, that organization is, for API purposes, a singleton. In that case, /organizations/:organizationId (the route, not the prefix) would not make a great deal of sense: it should either be just /organization or not exist, and be removed as a prefix from other things.

This reasoning can be applied to the rest as well.

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#23
post #16
post #3

Just do: - /organizations/:id - /blogs/:id - /sections/:id - /threads/:id - /comments/:id Why? What determines how resources are related are links, not patterns in the URL. It's a graph, the URLs are just nodes, the links are what connect them. If you _want_ to have some sort of hierarchy in the URL, you can redirect: - /organizations/123/blogs/1234 -> /blogs/1234 Then each resource expresses how it is related to oth…

> - /organizations/:id > - /blogs/:id The pragmatic, large-company-only counterpoint is the narrow edge case where: - :id must be human-readable for "SEO reasons" - there are many competing organizations and blogs to the point where there may be a name collision. Although in that case, I'd still suggest: /:organization-name/:blog-name

What if the company changes name?

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#24
post #15

Earlier quoted context omitted.

In some cases there might be a next stage of complexity where you have users with access to multiple tenants who are browsing them in different tabs. Then putting the organization as the top level in _every_ URL helps signal intent; otherwise you have to take other precautions that someone isn't on a tab with Organization A, clicks "Post new article" button (-> POST /articles) and happens to have their session logged…

(edit, see mnutt's reply) I'd really recommend putting the organization name in the content of the page in that example. Users don't really look at URLs, browsers de-prioritize them and often only display part of the URL. Also, depending on front-end implementation the REST API URL may not be displayed in the URL bar. A single page app may use example.com/#create-article for posting an article. A mobile app wouldn't…

In the above example the user saw they were on an Org A page and clicked Create intending to create an article in Org A, but sometime after they loaded their Org A page their “current tenant” session variable had been switched out from under them by a different tab.

One solution is to always pass the intended org along in the POST, but requires something disciplined and nesting POST /org/A/articles is one way to do that.

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#25
So, I generally do it the nested way: organizations/:organizationId/blogs/:blogId

The other post on this thread are accurate, in that normally keeping it simpler is better, but in this case I disagree.

With the nested approach you have the ability to do multiple levels of validation and mitigate a lot of key guessing attacks.

Imagine a different scenario:

facility/:facility_id/provider/:provider_id/patient/:patient_id

Vs

patient/:patient_id

In the first case there are three tokens I'd need to possess or guess in order to access a patient record. In the second, there's just one.

The implementation will still only grab the patient id for the query, but it'll validate that the two other keys are correct as well.

It also makes role scoping easier. I.e. my role grants admin access to all patients in a facility. Middleware to validate the access is a lot easier to implement if you have all those keys in the query string. Declarative permissions on the routes are a lot easier.

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#26
post #17
post #3

Just do: - /organizations/:id - /blogs/:id - /sections/:id - /threads/:id - /comments/:id Why? What determines how resources are related are links, not patterns in the URL. It's a graph, the URLs are just nodes, the links are what connect them. If you _want_ to have some sort of hierarchy in the URL, you can redirect: - /organizations/123/blogs/1234 -> /blogs/1234 Then each resource expresses how it is related to oth…

Yep this is it. If you nest IDs you just end up burdening all consumers with having to mimic your hierarchical structure when they don't need to.

It's worth noting that hierarchy itself isn't the problem, only hierarchy that isn't necessary for identifying a resource. If you happen to start comments on every post from 0 -- something like a (post_id, comment_id) primary key constraint on your comments table -- then it's natural to have a `/posts/1/comments/2` structure for your URLs. Under this data model, if you just had `/comments/2`, you wouldn't know enough to actually identify the comment -- just that it's the second comment on some post.

Whether it's a good idea to use this kind of composite key is a separate question, though.

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#27

Why reinvent the wheel? Just use a common standard... I prefer https://jsonapi.org/ .

jsonapi solves some problems, and introduces so many more. As a standard intended to reduce bike shedding, I have never had as many bike-shedding discussions as I have with jsonapi. Include syntax, plural vs single resource naming. sorting syntax... the list goes on. And worst of all... you cannot represent an API backed by jsonapi with swagger/openapi... a more common standard.

If you want jsonapi, you probably really want graphql...

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#28
One way to think about it might be to think of REST as RPC rather than folder nesting. E.g. `/[param_name]/[value]/..`

So if you can find blogs just by their blogId, then `/blogs/:blogId` makes sense since you only provide the necessary parameters. `/organizations/:organizationId/blogs/:blogId` would imply that `blogId` is not unique across organizations. This may also make sense if that's how it is.

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#29
post #27

Why reinvent the wheel? Just use a common standard... I prefer https://jsonapi.org/ .

jsonapi solves some problems, and introduces so many more. As a standard intended to reduce bike shedding, I have never had as many bike-shedding discussions as I have with jsonapi. Include syntax, plural vs single resource naming. sorting syntax... the list goes on. And worst of all... you cannot represent an API backed by jsonapi with swagger/openapi... a more common standard. If you want jsonapi, you probably real…

If you're comparing JSON:API to GraphQL then yes, there are some more decisions to be made, like filtering and sorting. (Includes are well specified in the spec- what bikeshedding were you doing?) But compared to not following a standard, you were going to have to make those decisions anyway.

> ou cannot represent an API backed by jsonapi with swagger/openapi

This doesn't seem right to me. What issues were you having trying to specify a JSON:API service using OpenAPI?

Re: Ask HN: Nested Resources in REST/HTTP API URLs?

#30
post #3

Just do: - /organizations/:id - /blogs/:id - /sections/:id - /threads/:id - /comments/:id Why? What determines how resources are related are links, not patterns in the URL. It's a graph, the URLs are just nodes, the links are what connect them. If you _want_ to have some sort of hierarchy in the URL, you can redirect: - /organizations/123/blogs/1234 -> /blogs/1234 Then each resource expresses how it is related to oth…

The data model matters doesn't it?

If it's /org/orgId/blog/blogId and a user has access to only a single orgId and needs to be logged in then doing it in /blog/blogId makes sense.

But if a user has acess to multiple orgs via different orgIds, then it makes more sense to do the former with /org/orgId/blog/blogId because then the page is sharable via URL. If you do just /blog/blogId that prevents a user from easily accessing a new organization (unless you use query parameters)

Post reply on HN