One approach says that you should keep your resource URL simple. We have verb in HTTP and resource name as path. So we can have:
GET /books/12
And if we want to fetch related collection, we might do:
GET /books/12/pages
On the other hand, there is a practice to use so-called resource verbs where you can fine-tune the verbs operation:
POST /books/12/bookmark
I would not use both approaches for my API. I tend to think that first approach is more correct (i.e. no verbs in resource name allowed), and to model the second approach we might use different entity, like:
POST /book-bookmarks/12/
or different id:
POST /bookmarks/12+book/
I know there is no true answer on this, but which one would be preferred? I would like to see some answers from people that actually went through design decisions like this one.
URI (or IRI) is a standard about indentifying resources. These resources can be web documents, real things, etc... In the current case they are web documents. Afaik. there is not standard about the URI structures, but URI standard along with HTTP standard suggest that you should use URIs and HTTP methods in a procedural way. So the HTTP verbs describe the procedure and the URIs identify the object of the procedure. Now you typically describe procedures with verbs and you typically describe objects with nouns. That's why it is logical to use only nouns in the URI structure, at least in the (hierarchical) path part of it.
(You usually can solve everything with the standard HTTP methods and proper nouns. Only in very special things can cause problems. In those cases I think it is better to use a new HTTP method than putting verbs into the URI. But that is really very rare. E.g. search with query string non compatible parameters e.g. files can be such a case. Another alternative approach in these cases to use POST and verbs in the URI.)
Related
Lets assume we have some main-resource and a related sub-resource with 1-n relation;
User of the API can:
list main-resources so GET /main-resources endpoint.
list sub-resources so GET /sub-resources endpoint.
list sub-resources of a main-resource so one or both of;
GET /main-resources/{main-id}/sub-resources
GET /sub-resouces?main={main-id}
create a sub-resource under a main-resource
POST /main-resource/{main-id}/sub-resouces: Which has the benefit of hierarchy, but in order to support this one needs to provide another set of endpoints(list, create, update, delete).
POST /sub-resouces?main={main-id}: Which has the benefit of having embedded id inside URL. A middleware can handle and inject provided values into request itself.
create a sub-resource with all parameters in body POST /sub-resources
Is providing a URI with main={main-id} query parameter embedded a good way to solve this or should I go with the route of hierarchical URI?
In a true REST environment the spelling of URIs is not of importance as long as the characters used in the URI adhere to the URI specification. While RFC 3986 states that
The path component contains data, usually organized in hierarchical form, that, along with data in the non-hierarchical query component (Section 3.4), serves to identify a resource within the scope of the URI's scheme and naming authority (if any). The path is terminated by the first question mark ("?") and number sign ("#") character, or by the end of the URI. (Source)
it does not state that a URI has to have a hierarchical structure assigned to it. A URI as a whole is a pointer to a resource and as such a combination of various URIs may give the impression of some hierarchy involved. The actual information of whether URIs have some hierarchical structure to it should though stem from link relations that are attached to URIs. These can be registered names like up, fist, last, next, prev and the like or Web linking extensions such as https://acme.org/rel/parent which acts more like a predicate in a Semantic Web relation basically stating that the URI at hand is a parent to the current resource. Don't confuse rel-URIs for real URIs though. Such rel-URIs do not necessarily need to point to an actual resource or even to a documentation. Such link relation extensions though my be defined by media-types or certain profiles.
In a perfect world the URI though is only used to send the request to the actual server. A client won't parse or try to extract some knowledge off an URI as it will use accompanying link relation names to determine whether the URI is of relevance to the task at hand or not. REST is full of such "indirection" mechanism in order to help decoupling clients from servers.
I.e. what is the difference between a URI like https://acme.org/api/users/1 and https://acme.org/api/3f067d90-8b55-4b60-befc-1ce124b4e080? Developers in the first case might be tempted to create a user object representing the data returned by the URI invoked. Over time the response format might break as stuff is renamed, removed and replaced by other stuff. This is what Fielding called typed resources which REST shouldn't have.
The second URI doesn't give you a clue on what content it returns, and you might start questioning on what benefit it brings then. While you might not be aware of what actual content the service returns for such URIs, you know at least that your client is able to process the data somehow as otherwise the service would have responded with a 406 Not Acceptable response. So, content-type negotiation ensures that your client will with high certainty receive data it is able to process. Maintaining interoperability in a domain that is likely to change over time is one of RESTs strong benefits and selling points. Depending on the capabilities of your client and the service, you might receive a tailored response-format, which is only applicable to that particular service, or receive a more general-purpose one, like HTML i.e.. Your client basically needs a mapping to translate the received representation format into something your application then can use. As mentioned, REST is probably all about introducing indirections for the purpose of decoupling clients from servers. The benefit for going this indirection however is that once you have it working it will work with responses issued not only from that server but for any other service that also supports returning that media type format. And just think a minute what options your client has when it supports a couple of general-purpose formats. It then can basically communicate and interoperate with various other services in that ecosystem without a need for you touching it. This is how browsers operate on the Web for decades now.
This is exactly why I think that this phrase of Fielding is probably one of the most important ones but also the one that is ignored and or misinterpreted by most in the domain of REST:
A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types. (Source)
So, in a true REST environment the form of the URI is unimportant as clients rely on other mechanisms to determine whether to use that URI or not. Even for so called "REST APIs" that do not really care about the true meaning of REST and treat it more like old-school RPC the question at hands is probably very opinionated and there probably isn't that one fits all solution. If your framework supports injecting stuff based on the presence of certain query parameters, use that. If you prefer the more hierarchical structure of URIs, go for those. There isn't a right or wrong in such cases.
According to the URI standard when you have a hierarchical relationship between resources, then better to add it to the path instead of the query. https://datatracker.ietf.org/doc/html/rfc3986#page-22 Sometimes it is better to describe the relation itself, not just the sub-resource, but that happens only if the sub-resource can belong to multiple main resources, which is n:m relationship.
My HTTP API has a method that updates resources found by filter. Practically it is a POST method, that utilizes a query string to find desired resources and transfers data in its body to update found resources:
POST /module/resources?field_1=abc&field_2=def&field_n=xyz
body: {
"desired_field":"desired_data"
}
I've heard it might be a code smell using a POST method and a query string together, but in the case presented above it seems perfectly reasonable to me.
Am I making wrong assumptions here?
Is it okay to use HTTP POST method with a query string, if a query string is used to find the resources that need to be updated?
Yes.
Am I making wrong assumptions here?
No.
The key ideas being that you, as the author of the resource, get to choose its identifier
REST relies instead on the author choosing a resource identifier that best fits the nature of the concept being identified. -- Fielding, 2000
the query is part of the resource identifier
The query component contains non-hierarchical data that, along with data in the path component (Section 3.3), serves to identify a resource within the scope of the URI's scheme and naming authority -- RFC 3986
and that the semantics of HTTP methods are standardized across all resources
Once defined, a standardized method ought to have the same semantics when applied to any resource, though each resource determines for itself whether those semantics are implemented or allowed. -- RFC 7231
When talking about resources, there's from a HTTP/REST perspective no difference between:
/article/1
/article?id=1
So if you do a GET request on either of these to get the article, you can do a PUT or PATCH on either of those to make changes.
However, the way many developers think of query parameters and POST bodies is often 'just a different way to send parameters'. This is incorrect, because they have a pretty distinct meaning, but using both at the same time may confuse some people.
So on a protocol level what you're doing is perfectly fine. I'd argue it's kind of elegant to use the URI as the locator and the body as the main message.
I am modeling blogging REST API which has resources Blog, Post and Comment with following URLs:
/api/blogs
/api/blogs/{blogId}
/api/blogs/{blogId}/posts
and I create separate endpoint for all Posts in and their Comment`s:
/api/posts
/api/posts/{postId}
/api/posts/{postId}/comments
Given that I have postId, what is the RESTful way to get Blog for a specific Post? I have three ideas:
1. /api/posts/{postId}/blog
2. /api/blogs/parent-of-post/{postId}
3. /api/blogs?postId={postId}
To me the 1. URL looks more "prettier" but the 2. option looks more "logical" since that endpoint (eg. /api/blogs/*) is generally for blogs resources.
The third option uses query string as parameter but the issue I have with it is that this endpoint would return different type of body depending on the parameter. Eg. without parameter /api/blogs returns a collection of Blog resources, while with parameter postId it would return just single instance of Blog. I am not sure if this is good thing to do (especially because I am using ASP.NET Core and C# which has strongly typed return objects, so implementation might be awkward).
what is the RESTful way to get Blog for a specific Post?
Real answer: anything you want.
REST doesn't care what spelling conventions you use for your resource identifiers. As long as your identifiers conform to the production rules described by RFC 3986, you are good to go.
/api/blogs?postId={postId}
This is a perfectly normal choice, and turns out to be a really convenient one when you want to use general purpose web browsers, because HTML forms already have standards that make it easy to create URI with this shape.
Your other two choices are fine; they lose a point for not being HTML form friendly, but it's still easy enough to describe these identifiers using a URI template.
The third option uses query string as parameter but the issue I have with it is that this endpoint would return different type of body depending on the parameter
General purpose API consumers do NOT assume that two resources are alike just because the spellings of their identifiers overlap each other.
Which is to say, from the outside, there is no implied relationship between
/api/blogs
/api/blogs/1
/api/blogs?postId=2
so the fact that they return different bodies really isn't going to be a surprise to a general purpose consumer.
Now, your routing framework may not support returning different types from the handlers for these resources (or, more likely, may not have any "nice" way to do the routing automatically), but that's an implementation detail deliberately hidden behind the REST API facade.
Similarly, the human beings that read your access log might prefer one spelling to another, to reduce their own cognitive load.
What's the most RESTful way to model an API which acts mostly as a GET, except that if the resource doesn't exist it creates it before returning it?
I can imagine using GET, although GET isn't supposed to change server state. I can also imagine using PUT, but in this case the resource should be immutable and PUT implies that the resource should be updated if it already exists. It can certainly be POST, but I feel like POST is the overused hammer to all impedance mismatch nails between API modeling and RESTful modeling.
Or should it be split into two separate routes outright? But that seems unnecessarily inefficient.
What's the consensus?
Typically, it is implemented as follows:
GET:Reads resource
POST:Creates resource
PUT:Updates resource
DELETE:Deletes resource
The common issue seems to be that get is limited on query string args. If you run against this limit, you may want to consider using custom headers. In either case, I would recommend that you follow the verb translations above.
Also, you don't mention the language. There is probably a framework that you can leverage that would abstract a lot of this from you.
When following a REST approach, which of the following GET requests is more correct:
v1/companies/10/employees/state=approved
v1/companies/10/employees?state=approved
There seems to be mixed use online.
Only the second approach makes sense to me. In a RESTful approach, you have to use the QueryString in order to filter the returned resources. In this case, add in your querystring the resource attributes that you want to use as filters. For example:
v1/companies/10/employees?state=approved&attribute2=value&attribute3=value
The first URI doesn't make any sense to me because you're doing a mix between URI and QueryString to filter the result.
v1/companies/10/employees/state=approved
Just to clarify, let's look at another example. The URI below only makes sense if "state" and "approved" are resources. But if they're only attributes from employee, then it's not RESTful. Remember, design your URIs considering that you're exposing resources rather than methods or actions.
v1/companies/10/employees/state/approved
I think it depends rather state is a resource or not. REST conventions are Controller/Resource/Sub -Resource, for example:
Books/Comics/SuperMan/FirstEditon rather than
Books/Comics/SuperMan?edition=FirstEdition
More readable, and indicates that FirstEdition is a resource rather than a state.