Restful API: Is it meaningful to send PUT without enclosed entity? - rest

Consider the following scenario:
There are two existing entity: shopping card #1 and item #1. I want to add item #1 to shopping card #1. There are two possible ways to design a Restful api:
1:
Without body:
PUT http://myshoppingsite.com/api/shoppingcards/1/items/1
Host: myshoppingsite.com
2: With body (having enclosed-entity):
PUT http://myshoppingsite.com/api/shoppingcards/1/items/
Host: myshoppingsite.com
{itemId: "1"}
Actually, I cannot decide which one is better and is more meaningful in terms of restfulness. Any idea?
(Note: I believe the http method should be PUT because of idempotency, but this is not my question here.)
PS: The problem I have with the first design is that there is no such enclosed entity in the request. Linguistically put is a transitive verb, so I expect somebody puts something somewhere. I think the same story somehow is in the HTTP world.

PUT is a HTTP verb that is supposed to create or replace the target URI, so this makes your first option immediately wrong. This request should replace all the items in your shopping cart:
PUT http://myshoppingsite.com/api/shoppingcards/1/items/
Since you want to add something to your shopping cart, this is not an option. This leaves effectively two options. First: the common one:
POST http://myshoppingsite.com/api/shoppingcards/1/items/
POST can mean many things, but in the context of REST services it's often used to append something to a collection. However, you mention that you want idempotence. You have two options here, first you can still use POST and within the context of your API guarantee that the request will be idempotent. Using POST does not mean that it's per definition non-idempotent, it just means that the HTTP spec alone does not guarantee it. That does not prevent you from making the request idempotent.
The other option is indeed PUT:
PUT http://myshoppingsite.com/api/shoppingcards/1/items/1
Your have a concern with that though, because in the context of your API you say that the request body would end up empty.
The reason for this is that you attach special to the last /1 in the url, and I think this what's wrong. If you want to follow REST best practices, then urls should not have any special meaning.
I think a saner way to do this, if you insist on using PUT is to get rid of the notion of "an id". That concept only exists in your database and should not make its way to the API.
Instead, I imagine that your service has a list of products such as this one:
http://myshoppingsite.com/products/1
To add a product to a shopping cart using PUT, this request might look something like this:
PUT http://myshoppingsite/api/shoppingcards/1/items/[completely-arbitrary-string-or-perhaps-a-uuid]
Content-Type: application/json
{
"product" : "http://myshoppingsite.com/products/1",
"quantity" : 5
}
Personally, I would just use POST though.
Q: there should be some information about the product you are addisng, no? Yes and that information is part of Uril. Why is it bad?
I'm not saying it's bad, I'm saying it's not RESTful. Pick up any book about REST and you will see this confirmed. This might also be a good place to start reading more about what REST is:
http://martinfowler.com/articles/richardsonMaturityModel.html
I would personally say that very little people build true RESTful services. This is why I also want to specifically point out that I don't want to say this is bad or good for your specific API, it's simply not RESTful.
What if I don't care about these principles and want to keep my special-meaning url scheme?
Well that's a fair point, but then we've gone beyond the original question here. If you want to design an API where the last bit of the url is actually the 'representation' of the item in your shopping cart, then yes I agree that having it also in the body is redundant.
In that situation I'd say, keep the request body empty. Just don't call it REST I guess.

Related

What should be the Rest URL for the action "Move the competitor from team1 to to team2"

I am looking for a good URL, following REST principes, to "Move the competitor from team1 to to team2
My first guess is :
/teams/{oldTeamId}/{newTeamId}/competitors/{competitorId}/move
But it doesn't look much like REST.
Should I break it into 2 basics calls ?
Remove competitor from team1,
Add competitor to team2,
Should I remove some data from URL and pass it into the body ?
I don't really know what to do for this one.
Think about how you would implement this API as a web site.
You would probably have a link to a form -- it might be a form where the competitor, old team, and new team are all blank, or it might be a form where the competitor and old team are pre-populated. Your consumer updates the default information in the form as required, and submits it.
Notice the first point (raised by Roman Vottner as well) -- your consumer doesn't need to look at the URL at all. The client knows the HTML form processing rules, so it can create the correct HTTP request without knowing anything about the domain.
The second point is that, since the client is just submitting the form to wherever the HTML tells it to, you can make that anything you want.
One of the interesting properties of HTTP is cache invalidation. See RFC 7234, any non error response to an unsafe request will invalidate all cached representations of one resource.
So you can choose which resource gets invalidated by specifying its URI as the target of the form. In effect, it gives you a mechanism for ensuring that a consumer can read its own writes.
So some reasonable choices for the target might be
/teams/{oldTeamId}
if the team roster is the most important thing. Or
/competitors/{competitorId}
if the resource that describes the player is what is most important.
I don't really know what to do for this one.
Concentrate on make it easy to use. Your resource model is not your domain model is not your data model.
It will likely be useful to watch Jim Webber's talk REST: DDD In the Large to get clearer insights into what your "REST" API should really look like.
To answer your questions, I would not break it into two calls, I would however take some data from that (GET) url and put it in the body of your request. The request would probably be a POST or PUT (or maybe even patch), but definitely not a GET since something is actually changing.
As for a solution, how about a POST request to a /transfer. After all you are (could be) creating a new transfer which takes for example the player, their new team and maybe their old team.
I would use URL to identify the resource which in this case seems to be a competitor's team.
So would
Make the url as /competitors/{competitorId}/teams
Make the call PUT
Have a body with newTeamId and if required the oldTeamId.

REST API Design for special actions on resources

I need to design an operation “duplicate” for "articles".
My thought was: a POST on apibaseurl/articles/{id}/duplicates and returning a 200 OK with the URI of the created duplicate, which's URI however will conform to the template apibaseurl/articles/{id}.
When issuing a GET to apibaseurl/articles/{id}/duplicates however, there will not necessarily be a list of duplicates (meaning: the server will not keep track of all duplicates created for an article - the "duplicate" relationship is ignored by the server outside the scope of the request)
Questions:
is my suggested solution OK?
does it not violate any RESTful principle by having the URI of the created object point to a location not under the resource under which it was posted?
would I have to provide a client with the possibility to list all duplicates for an article?
is my suggested solution OK?
It looks fine to me.
does it not violate any RESTful principle by having the URI of the created object point to a location not under the resource under which it was posted?
No, that is not necessary. You POST to a collection resource but this does not force you to return a Location header pointing inside this collection.
would I have to provide a client with the possibility to list all duplicates for an article?
If you have a use case for this, you could provide it. But if there is no business interest in listing the articles created as duplicates of an existing article, you don't have to.
Go ahead :)

REST API + hacks/REST + RPC hybrid. Do I get it right?

TL;DR How to mix REST requests with some non-REST requests in SPA(frontend/backend)? Or might be I just get REST wrong?
We are planning new API for SPA and mobiles(plus probably some 3rd parties). There will be some requests which, I suppose, can't be covered by REST.
I am speaking mostly about requests which would make backend do something, which would modify state of document or give some additional info, based on document, but request itself is rather simplistic.
Here is really easy example. I want to add a comment to blog post. For example I might do it like this:
Create comment. POST /comment
Create connection between author and comment. POST /comment_author or PUT /comment with author_id.
Create connection between comment and post. POST /comment_post or PUT /comment with post_id.
I also could do something like POST /comment with {author_id, post_id} which actually seems most logical here.
Everything did work, comment added to blogpost and associated with author.
Now customer wants to get statistics for his comment, like words stats and letters stats. As a part of request I pass comment_id. Backend might update comment with stats data, it might create separate entity and link it with comment or it might just send me those stats for this comment without saving.
So what would be the choices?
I can do something like:
GET/PUT /comment/:id/stats. For me it seems already hack, because as a result I don't want a document of type comment, but document of different type. As well as I don't send stats with request, I calculate them on backend so using PUT seems wrong.
POST/GET /comment_stats/:comment_id. Seems legit, but if I don't have a document/entity of type comment_stats, that would mean that I actually ask backend to create something, backend would reply me OK/Created, but actually I don't have this document somewhere saved.
So, while I understand REST != CRUD, I thought to use REST for simple CRUD and, for cases like that, to use RPC. So in RPC scenario I would just call POST comment.stats(comment_id)
My questions are what would be better choice in this situation, as well as are my thoughts about rest/rpc right?
I would go with GET /comment_stats/:comment_id for proper separation of concerns, so that report code doesn't clutter the comment resource.
It doesn't matter if you don't actually have a comment_stats document, or how the data is represented on your backend. The REST API is just an abstraction over your backend.
In general, for any non-CRUD action like this, it's better anyway to create a new resource and deal with it as if it was a "machine": you send some instructions to the machine (via a GET or POST call). The machine executes it and then returns the result. A simple example would be an endpoint to convert images: you create an /image_converter end point (the machine), you POST an image to it, it converts it, and sends back the image. /image_converter would have no associated entity/document in the database but for the end user it's still a resource with a logical behavior.

Proper way to structure my REST api in this case

I am trying to build a little web application with the MEAN stack (MongoDB, ExpressJS, AngularJS and NodeJS).
My question is very simple. If you take the example of a blog, it will contains blog posts, that you could list at this url:
GET /api/posts
You could also get the comments for that posts:
GET /api/posts/:postId/comments
and get a single comment:
GET /api/posts/:postId/comments/:commentId
The relation between post and comment is really obvious here, but does it still makes it mandatory to have it this way? or could I just perform my CRUD operations through /api/comments? In the end, a comment object in mongodb will always have a postId attribute anyway which will reference the post that it is related to... Moreover, the API will not be exposed and is strictly meant to be used by the application.
does it still makes it mandatory to have it this way?
No. This is not mandatory at all.
or could I just perform my CRUD operations through /api/comments?
Yes. This will result in cleaner resources URIs (endpoints).
You can also get post-specific comments with:
GET /api/comments?postId={postId}
Further, you could also drop the /api prefix if you are serving only an API at the given host.

REST API: Best way to do/undo an action on a resource

Note: I consider here that POST means "create" and PUT means "update", as GitHub does. This is not the place to argument in favor of POST or PUT.
I have a company resource and an assign action. I'm wondering how to translate this behavior in my REST API.
I thought about something like:
PUT /company/:id/assign
user_id: 5
What about if I want to unassign this user?
Should I use a boolean as a parameter?
Should I use an unassign action?
Should I use use another HTTP verb?
On the latest GitHub API I saw how to star a gist:
PUT /gists/:id/star
Why not, but how to unstar a gist:
DELETE /gists/:id/star
It seems pretty strange to me. You are updating an action on a resource and deleting it. Weird. I could understand whether POST instead of PUT.
POST /gists/:id/star and DELETE /gists/:id/star seems more logic to me. What do you think?
EDIT: I'm going to work with POST and DELETE. But as this is not possible to send data with the DELETE method, I have to pass the user_id in URL:
POST /company/:id/assign/:user_id
DELETE /company/:id/assign/:user_id
Using a boolean is not really clear. I could consider it as a non-obvious argument term. Consider that the most the API interpretation is obvious, the most your syntax is good.
Using the DELETE method is, finally, the best option you can choose. When you assign a user to a company, you create a relation. When you want to unassign, you delete the relation.