I'm developing a game website where accounts have characters. I'm using the routes:
account/{action} //execute `action` on the current account
character/{name}/{action} //execute `action` on specific character
But I need to delete and undelete (they are soft-deleted) characters, and while using a form is the right way for delete, it becomes unnecessary (is it?) bloat when I can use just a GET link to character/{name}/delete. Also, there is no verb for undeleting/restoring.
What is the correct and easy way (or both if there isn't the perfect way) to workaround this?
You could have a RESTful version if your URLs have nouns instead of verbs, such as :
character/{name}/achievements or
character/{name}/travels
To solve your active/inactive account problem, you could do :
GET/PUT account/activity
Already not restful, in which you are determining the action based on the route, not based on the verb. So that said, make a new route that is undelete (i.e. character/{name}/undelete), your already not REST so another route shouldn't matter. If you are looking for RESTful then the route should stay account/{character} and the verb determines the action(i.e. GET,PUT, POST DELETE to the same route). Now since you are not actually deleting, I would learn towards a POST (or perhaps PUT) for both i.e. updaing the entity to delete (or inactive), or updating it to undelete (active again)
Related
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.
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 :)
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.
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.
I have a scenario where I have to either
Pull the data from backend as search
Pull the same data from backend to administrate
The URLs I am using are -
/cars
/cars/management
The search can be then subsequently filtered as
/cars?color=blue
The concern that I have is that management is not a resource - it is actually an action. The management page contains links for other functionality associated with car management [add a car/delete a car/list cars/modify cars etc]
Has somebody else faced this issue? Can you let me know your solution?
There is nothing wrong with having a management resource that is a page showing management options for cars. Just because "cars" is the only thing in your database doesn't mean that is the only resource you can present to the user. You could have a resource that is just a form to pick a color (that makes a POST or PUT to the car resource). You could have a resource that is just a form to fill out the address you want the car delivered to. You could have a resource that is just a check box whether you want leather seats or not. You can have as many resources as you like and that make sense, even if all the resources are are pages with forms or links back to the car resource.
Just don't put any verbs in your URLs. You should still be using state transfer using HTTP verbs to change the state of the resources. Don't have a link like
GET /cars/123/deleteCar
on the management page. Instead there might be a link on the management page that (probably using Javascript since browsers have poor native support for HTTP verbs) performs a HTTP request along the lines of
DELETE /cars/123
when the user clicks the link. Something like jQuery can help with that. So long as the management page is using the HTTP verbs to change the state of the resources you are following REST since HTTP is a REST constrained protocol. REST doesn't say don't have actions, it says the actions should be constrained to state transfer.
There is no such concept as a "RESTful URL";
There is no issue with your URLs(/cars, /cars/management)
"/cars/management" is valid resource and it is not an action at all.
The RESTfull way to do this is to use the same URL with different HTTP verbs:
GET /cars for search/listing.
POST /cars for insert.
PUT /cars?id=123 (or /cars/123) for update.
DELETE /cars?id=123 for delete.