How to deal with restful "actions" on an object. - web-services

So I want to know what are the best practices for doing actions on a object that doesn't change the state of the object. If that doesn't make sense bear with me, I think the tweet example explains what I am trying to say.
I understand the basics like described here:
What are the best/common RESTful url verbs and actions?
And how it works when updating/getting/deleting etc an object. But what about actions that don't change the state of the object?
For example say we have a tweet object:
GET `/tweets (gets a list of tweets)
GET `/tweets/new (gets a new page to create a new tweet)
POST `/tweets (posts data to server to create new tweet)
GET `/tweets/:id (get a single tweet)
GET `/tweets/:id/edit (get a page to edit an exisiting tweet)
PUT `/tweets/:id (put data to server to edit exisiting tweet)
Delete `/tweets/:id (delete an exisiting tweet)
This makes sense to me. But how do i form the URL for reply/ follow / retweet/ favorite, some of which don't actually change the state of the tweet?
Should I do something like below?
POST `/tweets/:id/reply (post the reply message to the server)
POST `/tweets/:id/follow (post a boolean? yes I follow?)
POST `/tweets/:id/retweet (again post a boolean?)
POST `/tweets/:id/favorite (ditto)
Or do a
POST `/tweet/:id/actions (Do a post with the action I want to take as a parameter)
Or is there no "standard way".
Anyways thanks for the help!

Great question.
As always, it helps to switch the framing to nouns instead of verbs. What are the resources you're acting upon when you reply/etc.? And can those resources be fetched/addressed also?
In each of the cases you mentioned, I think the answer to the second question is yes. And in fact, Facebook's Graph API and GitHub's REST API both follow this approach.
E.g. for replying:
GET /tweets/:id/replies to get a list of tweets that were in reply to the given one
POST /tweets/:id/replies to create a new tweet in reply to the given one. The important part here is that success is a 201 Created w/ the Location header set to the created tweet's endpoint, e.g. /tweets/1234.
(Deleting a reply is then just deleting a tweet.)
Following/retweeting/favoriting are a bit trickier because the "nouns" are lightweight connections, and in fact, I just asked a Stack Overflow question for the "best" way to expose those:
RESTful API design: best way to CRUD lightweight connections?
You can see on that thread the specific way(s) you might implement following/retweeting/favoriting.
Hope this helps!

Related

API RESTful Resource Naming

I always have the doubt that you can see below when i need to create theresource URLs for a REST API. I wonder if some one can help me.
Let's suppose that i have two models.
User
Post
User can submit his own posts and can comment his own and another posts.
Main resources URLs for User would be:
GET /users # Retrieve all users.
POST /users # Create a new user.
GET/DELETE/PUT /users/{user_id} # Get, remove and update an user.
Main resource URLs for Post would be:
GET /posts # Retrieve all posts.
POST /posts # Create a new post.
GET/DELETE/PUT /posts/{post_id} # Get, remove and update a post.
My problem come when for example i want:
Top 10 submitters (filter for a parameter(external link, discussion, all)). The URL should be:
GET /users/top?type=ext
GET /users/top?type=disc
GET /users/top # for all
Or maybe it should be:
GET /users?top=ext
GET /users?top=disc
GET /users?top=all
The same but with posts:
Top 10 commented post (filter for a parameter(external link, discussion, all)). The URL should be:
GET /posts/comments?type=ext
GET /posts/comments?type=disc
GET /posts/comments # for all
Or maybe it should be:
GET /posts?top=ext
GET /posts?top=disc
GET /posts?top=all
Any of above options are good for you or it should be another way?
Regards
I like to think of the REST URI as a model representation in itself.
So /users/top doesn't make a lot of sense but /posts/comments seems to be fine (as comments could also be a different model). But for your case, I recommend other set of query parameters as they're widely used for filtering & sorting requests. So in your case, I'd recommend something like:
GET /users?sort=ext&order=desc&limit=10
which would help me understand that I'm requesting 10 user resources which have been sorted for ext in the descending order. (you can even change it to type=ext if you want)
As usual; REST doesn't care what spellings you use.
One place you might look for inspiration is... stack overflow itself. Do these URI look familiar?
/questions?sort=newest
/questions?sort=featured
/questions?sort=votes
The API has pretty decent documentation, which will also offer hints at decent spellings to deal with paging and search ranges.
That said, IMDB takes a different approach - The Shawshank Redemption uses a straight forward "I am an element of a collection" spelling
http://www.imdb.com/title/tt0111161/
But the top rated titles of all time? they appear as a chart
http://www.imdb.com/chart/top
But i want to know if there is a standard according to #Hawkes answer or there is no standard at all.
No standard at all; just local spelling conventions. Which is, to some degree, part of the point of REST: the server can use whatever spellings for URI make sense, and the client just "follows its nose" based on its understanding of the processing rules for the media type and the data provided by the server.

Correct REST API URL format for related objects

I'm designing a REST API where, amongst others, there are two objects.
Journey
Report
For each Journey there are many Reports enroute, and each Report has exactly one associated Journey.
A user might create a Journey using the API as follows...
POST /journey/
Then retrieve the details...
GET /journey/1226/
The first question is, if a user wanted to post an Report to their Journey, which is the 'correct' URL structure that the API should impose? This seems intuitive to me...
POST /journey/1226/report/
...or is this the case...
POST /report/
...whereby in the latter, the Journey ID is passed in the request body somewhere?
The second question is, how might one go about implementing the first case in a tool such as the Django REST framework?
Thanks!
The URL/URI structure is almost completely irrelevant. It is nice to be able to read it, or easily change or even guess it, but that is it. There is no "requirement" official or unwritten how they should look like.
The point is however, that you supply the URIs to your clients in your responses. Each GET will get you a representation that contains links to the next "states" that your client can reach. This means the server has full control over URI structure, the client usually has to only know the "start" or "homepage" URI, and that's it.
Here is an article which discusses this question, has some good points: http://www.ben-morris.com/hackable-uris-may-look-nice-but-they-dont-have-much-to-do-with-rest-and-hateoas/
Pass for the second question :) I didn't use that particular framework.

In Rest, what does "Treats the addressed member as a collection in its own right and creates a new subordinate of it." mean?

I was reading this answer, and it says this:
When dealing with a Member URI like:
http://example.com/resources/7HOU57Y
...
POST: Treats the addressed member as a collection in its own right and creates a new subordinate of it.
...
I've googled for this and found lots of results that say this exact quote, but none of them explain what it means. Can someone elaborate and use examples?
Bogdan's answer is correct on what the answer you refer to means, but that answer is a little misleading, because REST is not CRUD with HTTP. POST is not a synonym for Create.
The semantics of the POST method is to do any action that isn't already standardized by the HTTP protocol. POST is the only method that submits the payload to be processed by the targeted resource itself, not by the server. In a way, you can say that with the GET, PUT, PATCH and DELETE methods, the resource isn't aware of what's happening to itself, the server does the whole job, but with POST, the server has to ask the resource to do something.
This means that any action using a POST method must be documented in some way. The clients can assume a GET, PUT, PATCH and DELETE request will follow the RFC 7231, but the final result of a POST will depend on the target media type.
So, if the documentation for the media-type of the resource at http://example.com/resources/7HOU57Y says that a POST will create a subordinate resource and return the URI, fine, that's what it should do. If the documentation says that a POST will launch nuclear missiles against targets in Russia, then that's what it should do. If there's no documentation, someone made a mistake.
You can use POST to create a resource when you don't know what ID to give it. So you POST it to a resource that acts as a builder of such resources, and the server allocates an ID.
POST to http://example.com/resources and a new resource is created and the server gives it ID 7HOU57Y. You get http://example.com/resources/7HOU57Y.
The new resource is a subordinate of the collection, like a file is to a directory, for example.
But if POST works like this, then POSTing to http://example.com/resources/7HOU57Y should get me a new resource subordinated to this one, like http://example.com/resources/7HOU57Y/XYZ.
This is what I understand from that answer you posted. Of course this is highly dependent on how your service works (e.g. I could specify POST as unsupported for resources like http://example.com/resources/7HOU57Y).

Create single and multiple resources using restful HTTP

In my API server I have this route defined:
POST /categories
To create one category you do:
POST /categories {"name": "Books"}
I thought that if you want to create multiple categories, then you could do:
POST /categories [{"name": "Books"}, {"name": "Games"}]
I just wanna confirm that this is a good practice for Restful HTTP API.
Or should one have a
POST /bulk
for allowing them to do whatever operations at once (Creating, Reading, Updating and Deleting)?
In true REST, you should probably POST this in multiple separate calls. The reason is that each one will result in a new representation. How would you expect to get that back otherwise.
Each post should return the resultant resource location:
POST -> New Resource Location
POST -> New Resource Location
...
However, if you need a bulk, then create a bulk. Be dogmatic where possible, but if not, pragmatism gets the job done. If you get too hung up on dogmatism, then you never get anything done.
Here is a similar question
Here is one that suggests HTTP Pipelining to make this more efficient
There's nothing particularly wrong with having a bulk operation that you POST to, to activate (it'll be non-idempotent so POST is the right verb) but there are some caveats:
You're making multiple resources, so you need to respond with multiple URLs. This means you can't use the redirect pattern: you'll have to send a list of URLs back in some form.
You have a problem in that bulk operations are often not very discoverable. Discoverability is one of the most important things about RESTfulness, as it means that someone can come along and figure out how to write a client without lots of help from the server author.
Dealing with partial failures when you've got bulk operations remains problematic. It's a problem with any other paradigm too (I've watched people tie themselves in knots over this when working with extensions to SOAP) so it isn't a surprise, but unless you can guarantee that all the creations will work, you're going to have to work out what happens when you make one resource and fail to make the second. (Also, if the bulk request wanted a third one done, would you go on and try that?)
The simplest approach is just to support one create per request; that's a much easier pattern to get right and is better understood all round.
There's nothing wrong with creating multiple resources at once with POST (just don't try it with PUT). It's not "un-REST-ful", especially if you create a representation for the bulk operation itself. I suggest you create an index resource at the same time you create the individual resources, and return a "303 See Other" to it. That index representation would then contain links to all of the created resources (and possibly error information if any of them failed).
POST /categories/uploads/
[{"name": "Books"}, {"name": "Games"}]
303 See Other
Location: /categories/uploads/321/
(actually, now that I think about it, 201 might be better than 303)
GET /categories/uploads/321/
200 OK
Content-Type: application/json
[{"name": "Books", "link": "/categories/Books/"},
{"name": "Games", "error": "The 'Games' category already exists."}]
In your case I would also go the /bulk resource way. But the pattern I would suggest is the following and from my understanding the most natural: Work with the 202 Accepted status code.
The idea of a bulk request is that the server should not be forced to answer immediately as this would mean client needs to wait until it's bulk request completed.
Here is the pattern:
POST /bulk [{"name": "Books"}, {"name": "Games"}]
202 Accepted | Location: /bulk/processing/status/resourceId
GET /bulk/processing/status/resourceId
entry = "REST in peace" | completed | 0 errors | /categories/category/resourceId
entry = "Walking dead" | processing | 0 errors ->
So, the client POSTs the bulk information to the server. The server just accepts them with a 202 which gives no guarantee about the processing state at the time of response.
But the server also provides the link to a status resource. Here the client can have a look on each of the created resources and the processing state. When finished the client can access the resource via the given link.
Error cases can be identified by the client and erroneous data might be resend by a PUT on the completed resource.
Finally, a good advice I am usually following is: Whenever you hit a resource in your design that cannot be mapped on a HTTP feature it is probably because of a missing resource.
Actually this is still a hot topic till today, But simplify things I almost of the time say there is always a batter suited scenario for each practice.
Eg:
1. If you are receiving the likes from a post you don't need the bulk as in case there is only one like per comment.
2. If you are receiving favorites comment the bulk can fit well by considering someone reviewing the comment he reads and check box all of his favorites and send it once.
Again this is based on my experience working with Restful API, and but currently for the sake of multi tasking and others things, me and my colleague we found our selves doing the bulk all the time in most MIS(Management Information System) we do. This is because modern days web app and mobile app that can do a lot of work and send the final results to the back-end, this way the back-end has little job to do as long as the data received don't violate the business logic.

REST services - exposing non-data "actions"

I understand how to use REST for doing general entity interactions - using urls names to map to entities and the HTTP verbs to map to actions on those entities. But what is the generally accepted way of looking at "actions" more like RPC?
For example, let's say I want to send a command for the device to reset? There's no real "entity" here or do I do something like POST to http://mydevice/device/reset?
/device/reset or /system/reset are ok.
The REST "design pattern" does encourage you to NOT use any verbs.. You could do:
POST http://mydevice/system/state
<stateType>RESET</stateType>
Related information:
How to create REST URL’s without verbs?
Threads tagged with restful-url
I don't think that's the case to use POST. The "RESET action" is a idempotent action (if you call it n times you will always get the same result), so IMHO you should use a PUT call instead POST (as POST is not idempotent).
Also, as you are Putting a resource, you can use
PUT http://system
<device>
<status>RESET</status>
</device>
or
PUT http://system/status/reset
But I think the first one is "more restful", since you are putting a resource, while the second one you just use the URL.
I usually name the entity "system" or something like that. So you do "/system/reset". You've chosen device so that works too.
But yea, I usually consider these types of actions to be updates, which would use the POST method. So I think you are right to POST to /device/reset