-- Photo by Omer Rana on Unsplash
When working on real production system recently I asked myself a question:
Should REST API be constrained ...
For further actions, you may consider blocking this person and/or reporting abuse
We can all picture what a “car” represents, but what does a “spot” mean in this context? A physical parking spot? If so, think about the real relationship between them as entities. I’d argue that a car can exist without a spot (what if it’s out being driven and another car gets put in the previous spot?) and that a spot can exist without a car (the car that used to be in that spot got crashed, now what?)
If each one can exist in your system without the other, then I think there’s no real hierarchy between them and having both a /car/{carid} and a /spot/{spotid} endpoint makes more sense.
Why don't use grapql instead.. You only need to design the query.. Not the endpoints..
Sure, but my post refers to REST API, of course you can use different technologies where you don't have this problem, but sometimes you're constrained to use REST.
Maybe I was not precise enough, please see my answer above.
I've been dealing with this lately with regards to shared user profiles. A user can be a member of any profile so long as they are invited, and can perform CRUD operations on entities owned by the profile.
Profiles have private items with all the standard CRUD ops, so I've gone with the "long approach:"
/profiles/:profile_id/items/:item_id
. In my case, I think this is semantically correct because a user should be operating in the context of a profile. If the given profile tries to update an item owned by another profile, I issue anunauthorized
response informing the user of the API that the given profile doesn't own the item.The short approach, on the other hand, has no sense of profile context. Though there are plenty of cases where the nested resources don't make sense, I think they are especially nice when a user of your API operates under a given context, such as a profile
I've been digging more and encountered this post from Google which also has a section mentioning the concern I described in my post as well as many other interesting ideas. You may find it worth reading too :)
Had same thoughts when started new product few weeks ago. Ended up with exposing sub object without the root eventhough the root can be extracted is like a postcode without an actual address to the mailman or the recipient. APIs are for people.
Either option is entirely logic and as a developer using your API I would understand both use cases. As long as it's well documented then both options are perfectly valid.
That said, spots and cars are seperate entities that could exist without each other. If you wanted to know where a car was at any given time then having spot id in the request to get that info seems strange.
I'd probably go for car/{carid} and spot/{spotId}
By saying in post that car is a part of a spot I mean that you cannot rent the same car in other spot or park it there as each spot is managed by completely independent company, same way you have flats for rent on Airbnb.
Aha! I see, sorry my misunderstanding.
Generally the concept of a resource should be fully decoupled from any middleware that generates the representation of that resource. A resource is a concept, and, while the representation is dependent on your architecture, the resource should remain conceptually independent and coupled only to the problem domain.
Additionally, it's recommended REST practice to try to make your URIs as still and unchanging as possible, as the concept of the resource should change very slowly if at all (see "Cool URIs Don't Change" w3.org/Provider/Style/URI). The representation of this resource can change as often as it want so long as it conceptually equivalent to the original resource.
Yes, this makes also a lot of sense. This reason would probably win if I am doing a publicaly available API.
I had the exact same thought because I had users, memberships, and organizations. Each membership connects a user with an organization, so each org can have multiple members and each user can be part of multiple orgs.
The basic RESTs are easy:
GET /users/:id/memberships
GET /organizations/:id/memberships
But it’s the same problem when thinking of a single membership:
You could GET /memberships/:id or have two endpoints, GET /users/:id/memberships/:mid and GET /organizations/:id/memberships/:mid. We chose the second, longer one and added the additional condition in the query because it felt semantically logical.
Discussing href structure has nothing to do with RESTful architecture. To be restful you need to be discussing the hypermedia controls between resources. URLs are irrelevant in RESTful.
It depends.
As far as I know there are 4 different maturity levels of REST according to Richardson. You're probably referring to 3rd level also known as HATEAOS. In practice I have never worked in project doing the API this way. Even big companies like FB or Google does not build their APIs this way because in most cases API clients don't need this kind of intelligence. So if your client needs this, then OK, otherwise it just adds too much work overhead and clutters the API.
Usually what I do is the 2nd level or maturity so I would not agree with your saying.
Moreover, please note that I am discussing href structure in context of service architecture (backend app design), not the REST architecture (multimedia headers, http methods, maturity).
It does not depend. Fielding gave one definition of rest despite what Richardson says. But EVEN if we take Richardson, not a single level mentions href structure so again..this has nothing to do with RESTful at all.
Google and fb build tons of RESTful services. Their entire html applications are RESTful. You are way off track here.
there is no such distinction between restful architecture and backend design as you say. RESTful goes from service to client, that’s a core tenant of its very definition. Try to think about your problem restfully and you’ll soon see why your questions are so confusing now. Your trying to model your problem domain with a broken language.
Ok, we have different opinions and I appreciate it. So what's the right API for my problem domain according to you and can you justify it?
That’s a fair question, lemme think about it today
Instead of focusing so much on the architecture constraints, I would concentrate on defining common use cases for my API. If a use case makes sense for my business, there is a big chance I will need to change your architecture, your db design or both.
Conceptually speaking, API resource ids should be decoupled from your legacy data models. Otherwise your API will eventually be limited and there would be not much room for API new versions.
In order to enforce that decoupling, when designing a new API, I always consider building an intermediate data model for my APIs that can bind resource ids with legacy apps ids.
Mostly I agree with what you wrote except decoupling API IDs from data model IDs. I've never seen this in practice. How would you achieve this? e.g. if I have a UUID in my DB record how would you translate it to API ID?
I like the shorter URL for a couple reasons:
I would add a version path just to make sure that the newer API will not break older users.
/v1/spots/{spotId}/cars/{carId}
Thanks for pointing this out. I prefer versioning using headers instead of path. In the initial release I do not require any version headers and then try to maintain API changes so that they are backward compatible as long as possible. Finally, if this is really a must to version the API then I would add version headers.
It depends I'm more towards your API should focus on use cases and general API best practices to make it easy for anyone to use your API.
Better documentation always doesn't hurt
Encountered this interesting podcast about RESTful APIs which is related to this discussion.