Proper route pattern for RESTful collections with additional resources - rest

I have been doing RESTful APIs for quite a bit (exposing and consuming 3rd parties) and I see two following patterns popping up here and there. Each has pros and cons and neither is "clean" in my opinion.
So the situation is: you have a collection resource (e.g. "assets") and you want to expose some additional resources within a collection (e.g. subresources of the collection itself, not the asset, like aggregated view endpoint or some commands).
Two patterns I see are:
People create a RESTful collection resource like /assets/${asset-id} and expose everything else they need like GET /assets/owned, GET /assets/summary, POST /assets/recheck-inventory. This looks neat and concise but introduces a clash between ${asset-id} and nouns of sub-resource URLs (e.g. asset12345 and summary are in the same place in the URL).
Others do /assets/items/${asset-id} and expose everything like GET /assets/owned, GET /assets/summary and so on. This is cleaner from routing perspective and a bit more future-proof, but adds an extra noun in the route, which leads to confusion when people are trying to do POST /assets for example.
The "best practice" guidelines I went through thus far avoid the question altogether. I also understand that REST is a convention and not the standard, and there is a universal "it depends" answer. Still, I feel like there got to be a generic recommendation here.
Hence the question is: which of two you would use?
UPDATE: to clarify, let us assume that:
/assets/owned contains entities of different types, not assets, so it is not a query and you can GET/POST/DELETE items in it.
/assets/summary is an aggregation document (e.g. report with quantities for example)
/assets/recheck-inventory is a command (i.e. POST only)
Also, we want to stick with REST principles:
route's path shall identify an entity and its state uniquely.
query parameters alter which elements are returned, but do not change the payload format.
headers are for protocol-level information and do not change service logic (i.e. presentation, security, caching, etc.)

I don't like these approaches either, but be aware, that REST does not put constraint on how to design URI structure, so you can do whatever you feel right. Apparently the developers of these webservices felt this approach right.
I would do something like the following with your URIs, since I like flat URIs much better.
/assets/items/${asset-id}
-> /assets/${asset-id}
/assets/owned
-> /assets/?owned
-> /assets/?owned=true
/assets/summary
-> /assets-summary
-> /assets/ + "Prefer: return=minimal"
You can find more about the prefer header here, but be aware, that you need to register it by the vary header if you want it to be a secondary cache key.

Related

What is the RESTful way to design URL that returns parent of a child resource?

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.

REST Best practise for filtering and knowing the result is singular: List or single?

Variety of REST practises suggest (i.e. 1, 2, 3) to use plurals in your endpoints and the result is always a list of objects, unless it's filtered by a specific value, such as /users/123 Query parameters are used to filter the list, but still result in a list, nevertheless. I want to know if my case should 'abandon' those best practices.
Let's use cars for my example below.
I've got a database full of cars and each one has a BuildNumber ("Id"), but also a model and build year which combination is unique. If I then query for /cars/ and search for a specific model and year, for example /cars?model=golf&year=2018 I know, according to my previous sentence, my retrieve will always contain a single object, never multiple. My result, however, will still be a list, containing just one object, nevertheless.
In such case, what will be the best practise as the above would mean the object have to be extracted from the list, even though a single object could've been returned instead.
Stick to best practises and export a list
Make a second endpoind /car/ and use the query parameters ?model=golf&year=2018, which are primarily used for filtering in a list, and have the result be a single object, as the singular endpoint states
The reason that I'm asking this is simply for the cleanness of the action: I'm 100% sure my GET request will result in single object, but still have to perform actions to extract it from the list. These steps should've been unnecessary. Aside of that, In my case I don't know the unique identifier, so cars/123 for retrieving a specific car isn't an option. I know, however, filters that will result in one object and one specific object altogether. The additional steps simply feel redundant.
1: https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
2: https://blog.mwaysolutions.com/2014/06/05/10-best-practices-for-better-restful-api/
3: https://medium.com/hashmapinc/rest-good-practices-for-api-design-881439796dc9
As you've specifically asked for best practices in regards to REST:
REST doesn't care how you specify your URIs or that semantically meaningful tokens are used inside the URI at all. Further, a client should never expect a certain URI to return a certain type but instead rely on content-type negotiation to tell the server all of the capabilities the client supports.
You should furthermore not think of REST in terms of object orientation but more in terms of affordance and statemachines where a client get served every information needed in order to make an educated decision on what to do next.
The best sample to give here is probably to take a close look at the Web and how it's done for HTML pages. How can you filter for a specific car and how it will be presented to you? The same concepts that are used in the Web also apply to REST as both use the same interaction model. In regards to your car sample, the API should initially return some control-structures that teach a client how a request needs to be formed and what options could be filtered for. In HTML this is done via forms. For non-HTML based REST APIs dedicated media-types should be defined that translate the same approach to non-HTML structures. On sending the request to the server, your client would include all of the supported media-types it supports in an Accept HTTP header, which informs the server about the capabilities of the client. Media-types are just human-readable specification on how to process payloads of such types. Such specifications may include hints on type information a link relation might return. In order to gain wide-usage of media-types they should be defined as generic as possible. Instead of defining a media-type specific for a car, which is possible, it probably would be more convenient to use an existing or define a new general data-container format (similar to HTML).
All of the steps mentioned here should help you to design and implement an API that is free to evolve without having to risk to break clients, that furthermore is also scalable and minimizes interoperability concerns.
Unfortunately your question targets something totally different IMO, something more related to RPC. You basically invoke a generic method via HTTP on an endpoint, similar like SOAP, RMI or CORBA work. Whether you respect the semantics of HTTP operations or not is only of sub-interest here. Even if you'd reached level 3 of the Richardson Maturity Model (RMM) it does not mean that you are compliant to REST. Your client might still break if the server changes anything within the response. The RMM further doesn't even consider media-types at all, hence I consider it as rather useless.
However, regardless if you use a (true) REST or RPC/CRUD client, if retrieving single items is your preference instead of feeding them into a collection you should consider to include the URI of the items of interest instead of its data directly into the collection, as Evert also has suggested. While most people seem to be concerned on server performance and round-trip-times, it actually is very elegant in terms of caching. Further certain link-relation names such as prefetch may inform the client that it may fetch the targets payload early as it is highly possible that it's content will be requested next. Through caching a request might not even have to be triggered or sent to the server for processing, which is probably the best performance gain you can achieve.
1) If you use query like cars/where... - use CARS
2) If you whant CAR - make method GetCarById
You might not get a perfect answer to this, because all are going to be a bit subjective and often in a different way.
My general thought about this is that every item in my system will have its own unique url, for example /cars/1234. That case is always singular.
But this specific item might appear as a member in collections and search results. When /cars/1234 apears in these, they will always appear as a list with 1 item (or 0 or more depending on the query).
I feel that this is ultimately the most predictable.
In my case though, if a car appears as a member of a search or colletion, it's 'true url' will still be displayed.

REST API on files

I'm trying to get an understanding of REST
You have a web server which allows operations on files, you can copy, print, merge, translate, delete, etc files (so, basically a whole bunch of verbs on the noun)
How does this translate into REST?
Can all/most RPC type interfaces be mapped to REST?
As long as you think of your data as a collection of resources that can be manipulated with GET, DELETE, POST, PUT, then yes.
It might require you to add more 'nouns' though.
You could treat some of these operations as their own resource.
For example, a POST to /myfile/copy would return a Location header with the URL of the new copy: /myfile(2) or something like that.
A process like printing could look like this:
POST the print config to /myfile/prints which would create a print job resource:
/myfile/prints/12345
a GET on /myfile/prints/12345 would give you the status of the print job.
a DELETE on /myfile/prints/12345 would stop the print job
The basic gist of REST is to provide a guideline for interacting with resources in a common way, in order to make discovery and interaction easier for callers. This is done by mapping logical API concepts to HTTP concepts.
At its heart, REST is all about resources. So, what's a resource? In a nutshell, it is a thing - a noun. Each resource should be represented by a unique URI, and each URI should represent one unique resource. This will typically follow the pattern of root/collection/item where that may sometimes repeat. For example: api.halo.com/players/SomeGuy/matches/1234. In the example, the noun, is a match that was played by a specific player. To reference it, we start at the root (api.halo.com) and go through the collection of players to reach the player named SomeGuy and then through the collection of matches that he/she played to get to the specific match (1234) that we're interested in.
Now that we have a resource, we want to do some things with that resource, such as look at it, replace the entire thing with a new one, update some properties of it, or maybe create a new resource. REST makes use of HTTP verbs to express the operation that you'd like to perform. For example, GET is used to indicate "hey, please give me this thing", POST indicates "hey, please create me a new thing", PUT indicates "please take my new thing and replace the thing you have with it", PATCH indicates "please update some of the properties of the thing with my new data", and DELETE indicates "please remove this thing.
In general, interfaces that deal with a single "thing" or a collection of a single type of "thing" are the ones that map most cleanly to RESTful design. That said, if you're creative enough, you can usually find a RESTful way to model just about all of the concepts that you'd be making RPC calls for, though tuning your API patterns to concentrate on resources and data will help a lot there.
One final call-out that I should make is that you're likely to find that there are many, many strong opinions on REST in the community. There are those that are very pedantic, black-and-white, about what qualifies as RESTful and what doesn't - and different schools of thought on what that is. There are just as many individuals that are apt to relax some of the concepts when needed but still consider their design RESTful.
My very general advice would be to concentrate on who the consumers of your API are and design something that helps them fall into the pit of success - doing the obvious thing and following well-established guidelines where possible, but making things as obvious and easy for them as you can when it doesn't line up so clean.
Here's a couple of things that may offer more introductory context:
Info Q: REST Introduction
H9: Introduction to REST
Pearson eCollege: What is REST?

URI of REST to reflect relationship of resources?

I knew some name conversions of REST API, for example resource name should be plural, using different HTTP method with same URI to perform different action on that resource, etc.
But as URI should reflect relationship of resources, I am a little confused. Take SO as a example, when update a existed comment of a answer, URI should looks like:
PUT /{contextPath}/questions/{questionId}/answers/{answerId}/comments/{commentId}
But I feel awkward when using this so-called standard URI because:
It's a little verbose, especially when the hierarchical is very
deep.
questionId and answerId is completely unnecessary here, since
commentId is sufficient for server to identify a comment record.
So what's the appropriate way to deal with this? should I always follow name conversions, or make some changes when the relationship hierarchical of resources is very deep?
I emphatically disagree that "URI should reflect relationship of resources".
URIs are pointers to resources. That's it. There are conventions for making them human-readable, and therefore easier to work with. There is certainly no hard-and-fast rule that relationships should be modeled on the URI path. Feel free to model resources in a flat, rather than hierarchical manner. Use links to model relationships between the resources, and query parameters to narrow down collections.
It gives you more Options without haveing to make extra requests.
Thus allowing you to call functions that might require say a questionId.
When you only have the commentId you have to first query your questionId.
Depending on what your functions require. If you had specific info on the previous page and have to use it again in the next why query it twice? Unless it is sensitive which an questionId clearly is not.
Thats my opinion on how you should look at your addoption of the standard
I would simplify the route/URI to:
PUT /comments/{commentId}
along with at the corresponding RequestBody, perhaps some sort of DTO.
The URI should not have to show the hierarchy all the way from the context path. It can be the shortest URI that can uniquely identify the resource

REST resource with multiple views

We are trying to follow a quite strict idiom for our REST service however we have come across a situation where we have two clients who require different representations of the same resource. One is front-end and they would prefer a very minimal resource with only the fields they require and in a more flattened structure (for performance), the other requires all fields that we have in our data store in a heavily nested structure. What is the idiomatic way for REST services to deal with this given the canonical URL should be the same as they are accessing the same resource. We thought of adding projections to the request but with this the structure would still be quite nested which causes performance issues in the JS client as it will have to walk through the structure and flatten it, something that can be quite costly when the number of resources returned is high.
I would suggest there are two alternatives:
1) If the query field can vary, you could specify the fields (structure) you want as query parameters. This is common in REST APIs. With no specification, you would return a default list of fields. What should be default or not depends on the service, but in general the minimal set makes a better default for performance. In order to avoid listing all fields, something like fields=all could be used. In your case structure might make more sense.
2) You can encode the field request in a custom request headers. Some would argue that this is the more REST-ful approach as you're only modifying the format of the response and not the underlying action invoked, and therefore the URL should be the same.
In practice, most services prefer the first approach as it's considered more approachable.
Personally, I think it's a marginal choice. I prefer to encode the return media (JSON, HTML, XML, etc.) in the Accept header. Any decent developer has tools that make it easy enough to set the headers, but the fields query parameter idiom is, in my experience, far more prevalent and there's a great deal to be said for convention.
Note, if you use the headers approach, you should probably not use the Accept header for the structure/field specification. Add your own header if you go that route.