Oftentimes when looking to design a REST API I see a common pattern of /resourceA/{id}/resourceThatBelongsToA.
Is it ok to do /resourceA/resourcesThatBelongToA when designing an API?
Reallife example
Say I have a web application similar to StackOverflow. There are questions, and each question has a status of accepted or not accepted.
I expose an endpoint /questions/{id}/status so that users can determine whether or not a question has an accepted answer.
I then run into the problem of wanting to discover all questions that have an accepted answer. I then define an endpoint /questions/statuses?status=accepted. This endpoint, when given no query parameters, will list all the statuses of all questions (with reasonable limits on the amount of statuses return, say 100). However, when given a filter of status type, I can determine all questions that have an answer that was accepted.
To me, this seems like a practical design that fits the use case well.
Is this an acceptable pattern to use or is there something more suitable?
Is it ok to do /resourceA/resourcesThatBelongToA when designing an API?
Yes.
REST doesn't care what spelling you use for your identifiers.
REST doesn't care how you organize your resource hierarchy.
Is this an acceptable pattern to use or is there something more suitable?
The heuristic I recommend is "would you do it this way with a web site?" If the answer is yes, then you are on the right track.
REST APIs look good when you have a unique id for the parent resource you are dealing with. /questions/{id} is good if you want to get the question resource with the particular id. But if you don't have a unique ID and if the response is going to be a set of resources, then it is just a filter applied to the parent resource.
So for your case, the API can be
/questions?status=accepted
If you want the api consumers to get the flexibility for choosing limits, you can use a query parameter limit for it.
/questions?status=accepted&limit=10
Related
I see in many different REST API docs the use of the me word like Imgur one. It enable this kind of route that looks very elegant:
GET /users/{id} -> Get public data from user {id}
GET /users/me -> Get my data if I'm connected
But is it actually 'REST valid'? Does it respect the REST convention?
There's not really a 'valid REST', or 'standard REST'. REST isn't officially really tied to using HTTP.
Is this a reasonable way to design an API? I would say so. Does it violate conventions/common-sense/HTTP best practices? I don't think so.
The way you design your URL structure is entirely up to you. It's usually only frameworks that enforce stricter conventions, but it doesn't mean your approach is wrong.
The downside of context-bound URIs as /users/me is that they are not shareable. So I'd say it's fine to have one for convinience but only to complement a corresponding unique URI like /users/{id}.
Say I have endpoints for GET /objects/{id}, GET /objects/{code}, and POST /objects, as prescribed by RESTful design, and objects have fields name and code (unique).
I want to consume the objects data in another app, particularly with autocomplete filtering on both name and code.
As I see it, the options are
GET /objects?q={user-input} where q is what the user is typing, and the backend does a SELECT statement with LIKE '%{user-input}%'
POST /objects/search with a JSON payload
Which is more RESTful? Are there other options?
It depends what my goal is.
If all my application does, beside "cruding" objects, is to search by autocomplete, and maybe some other fixed search, I would use a specific endpoint and action.
GET /objects/autocomplete?prefix=<>
It may look strange, since this is at all not RESTful, but my point is to make a simple and specific endpoint, in case this is all your application is about.
But of course if the app needs to support more flexible filtering, I would choose a POST request with the filters in the payload.
POST /objects/search
Both are not necessarily very RESTful, and in my opinion REST is not always the best strategy, more important is the use case. Anyway the object "cruding" and relations actions ARE (RESTful), so I would leave these untouched, this is why you may prefer /objects/search over just /objects (in both GET and POST), to make sure you don't affect the domain.
You can read more in depth here :https://softwareengineering.stackexchange.com/questions/353086/what-is-a-proper-way-to-do-a-complex-restful-search-method
I was thinking of how to make a RESTFul API more intention revealing. A common patter I see around various blogs on this is that conventional REST API results in
Ban a Player -> POST /players.
But I were to change to a more intention revealing interface , I could use
Ban a Player -> POST /players/{ playerid }/banPlayer
The second one I feel is more intention revealing.
The common objection I get from the team is that the second one does not comply with start REST style.
Also currently I cannot move away from a RESTful API.
I would like to hear your thoughts on this.
With Restful API design there are two schools of thought around how to apply actions to a resource.
You describe the action to be taken against the resource in the Uri:
Request Uri:
POST /players/{id}/ban
Note: Just use ban - we already know the resource is a player, its in the base Uri.
You can have the action in the body of the request:
Request Uri:
POST /players/{id}
Request Body:
{ 'action': 'ban' }
You can pick either way - whichever you prefer, there is lots of discussion on both but ultimately both are correct.
Note:
My assumption here that banning a player is more than just updating a part of it, but rather a system action (or state transition) relating to the player. Otherwise if it was just an update to the player resource you should handle with a PATCH or PUT as appropriate.
Some discussions for reference:
http://restful-api-design.readthedocs.io/en/latest/methods.html
https://github.com/interagent/http-api-design/issues/58
https://nordicapis.com/designing-a-true-rest-state-machine/
https://softwareengineering.stackexchange.com/questions/141410/restful-state-changing-actions
With plenty more if you do some Googling...
Long story short: it shouldn't be mandatory to be intention revealing but if you want to add some DDD on how this API looks like then it is nothing that prevents you from doing that
According to HATEOAS constraint of a RESTful web API (this constraint is an essential part of the "uniform interface" feature of REST, as defined in Roy Fielding's doctoral dissertation), the software clients of your API should not care about the URLs. Every possible&permitted action should be included in the response, with the corresponding link relation and URI. In this way you have to hardcode only the link relations.
This constraint does not however prevent you from making the API more intention revealing for the Human clients that try to understand the overall architecture. I recommend you to choose this path, as Human users are at least as important as the software that they write.
Roy Fielding wrote about this on his blog post.
Since you asked for the RESTful way not the best way, here's my thoughts.
Your RESTful URI options include:
/players
/players/{ playerid }/banPlayer
/player-banning
/entities?action=ban_player&method=PUT
/banana
anything else, REST doesn't dictate what your URIs should look like
The RESTful way is to expose knowledge of the next available states purely through hypertext. To do REST, you must use Hypertext As The Engine Of Application State (HATEOAS). Relying on client knowledge of the URI is depending on out-of-band knowledge, which is antithetical to REST.
Your resources do not need to map directly to your business objects. If you choose, you can represent user intent itself as a resource, e.g. a banned player event resource. You can POST to it with some info on which player to ban, and subsequent GETs will provide information on the event.
Oh and just because REST doesn't care what your URIs are, doesn't mean you shouldn't. You'll just have to use a different standard to decide what's best.
According to the REST API approaches, you need to use your entities in URI, so, as banPlayer is not an entity, you cannot use it.
I suggest to UPDATE your record with PUT method.
Here you can read more about rules. Actually, the first section about URIs is just about your case.
The common objection I get from the team is that the second one does not comply with start REST style.
The easy answer is this: consistency in the API has value, whether REST or not. So "that's not how we do it here" is going to trump "but REST says".
The spelling of URI in an API is a lot like the spelling of method names in your code. There are a lot of different arguments for different styles, but "local convention" is a strong argument by itself.
That said -- REST does not care what spelling you use for your identifiers.
This is what Fielding had to say in 2008
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. Any effort spent describing what methods to use on what URIs of interest should be entirely defined within the scope of the processing rules for a media type (and, in most cases, already defined by existing media types). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]
In band would be including the URI in the representation of the resource -- putting it into the description of a form in the HTML document. Out of band is documenting the URI, and expecting people to do the right thing with it.
Note: there's nothing wrong with human-readable URI, or documenting the URI that should be used. But notice that you can post questions to stackoverflow even though the people who wrote your browser didn't read stack overflow's API documentation -- that's REST.
This Google Cloud article API design: Understanding gRPC, OpenAPI and REST and when to use them clarifies the REST vs RPC debate. REST is more relevant for entity-centric API whereas RPC is more relevant for action-centric API (and CQRS). The most mature REST level 3 with hypermedia controls works well only for entities with simple state models.
Understand and evaluate first the benefits of REST for your case. Many APIs are REST-ish and not RESTful. OpenAPI is actually RPC mapped over and HTTP endpoints but it doesn't prevent it to be widely adopted.
I'm creating a service with RESTful APIs which will be responsible for serving Oracle transaction logs. The service will provide GET and DELETE APIs to fetch/delete transaction logs in a given time range.
For creating APIs, I have 2 options:
GET: /table/{tableName}/logs?startTime=<>&endTime=<>
or
GET: /logs/table/{tableName}?startTime=<>&endTime=<>
similar for delete use case.
Which one of these would you pick and why?
To be fair, REST is fairly open to interpretation as far as what is "correct" but I would probably go with the first option. I think that the URL should be designed in a somewhat logical order. First, you are looking at a table, then looking at a specific table, then looking at that table's logs. This makes more logical sense. Secondly, when you do the query at the end of the URL, the query is really on the logs so having the query as close to the word logs as possible makes the most logical sense.
REST does not say anything about the correct structure of your urls. In fact, it suggests that urls should be discovered and irrelevant to clients. It's considered a best practice to create a logical URL structure, but this is only intended useful for humans and not for REST clients.
Which is better is completely subjective but either is correct in terms of REST based design.
Correct REST design principles make me tired. There are a lot of very emotional arguments about these. So I don't know what is correct in terms of REST based design, but I do know what I would choose:
I would go with /logs/table/... if you have another log-related resource other than tables. If not, I would go with /table.
By the way, why table and not log? The resource is a transaction log, isn't it?
I just began looking at REST and was wondering what the basic difference between the two representations was. The first one looks pretty nice to me and the second one has to pass some attribute values but the underlying logic seems to be boiling to almost the same thing (I could be mistaken though)
http://url/category/category_id/item_id
AND
http://url/category?category_id={12}&item_id={12334}
I think you are labouring under some fundamental misconceptions about what REST is about.
The URL used to access a resource really is a detail and actually should not matter to the client. URL's should really be "discovered" by clients anyway if they follow the HATEAOS principe that is one of the tenets of REST.
Essentially you are right though: either URL could represent the resource you are exposing in the end, but as I say, this really is a detail and it comes down to preference in many cases at what URL you expose something. The point of HATEOAS is to allow you to change the URL's that are used to access resources at-will without affecting clients that work against your existing services.
The following URL's might help you understand some of the properties that make services truly RESTful:
How to GET a cup of coffee
Describing RESTful Applications
[disclaimer: just because HATEAOS is a principle of REST does not make it easy to do. You will find most of the services on the web do not follow this principle strictly at all, as evidenced by their documentation which is full of URL templates; not the way services should be documented in the ideal world. I'm struggling myself to find good examples of truly RESTful services and clients...]
It should be possible for agents to reason about the resource structure:
based on the URL, and
based on links returned by requests for resources.
The problem with the second representation is that it can be considered as a set unordered keys and values, with no real structure/heirarchy.
If you click the button from your tag restful-url you get a good link from this site explaining the difference between those two styles:
How to obtain REST resource with different finder "methods"?