Learn REST: A Tutorial
rest.elkstein.org
rest.elkstein.org
As a contrived example, say we have a booking
GET /booking/:id
And we then want to cancel this booking, more specifically we want to trigger the "cancel" action (transition), which would change the state of the booking from "active" to "cancelled". There are a few possible ways to do this, and I'm not really sure which is "correct" for REST, or whether it actually matters: POST /cancel (booking = /booking/:id)
PUT /booking/:id (state = cancelled, note this is dictating the resulting state, not the transition)
POST /booking/:id/cancel
CANCEL /booking/:id (custom verb, good/bad ?)In general, it is not wrong to noun-ify domain concepts such as a cancellation.
Sidenote: Is it "better" to pass booking_id = number, or booking = booking resource URL. Why?
The problem isn't so much REST, but HTTP: using a custom method could have the potential of creating havoc with proxies and such.
> Sidenote: Is it "better" to pass booking_id = number, or booking = booking resource URL. Why?
I think the ID should be the URL. It decouples the client from the internal IDs, which is not only DRYer (since otherwise you'd effectively have two IDs) as it can help if you need to change the internal ID format.
DELETE /booking/:id
Which is basically a more correct HTTP version of your last option. Otherwise, I would lean towards your second option (the PUT), as I would think that what you are doing is telling the server what you want the state of the booking to become. What happens server-side based on the PUT isn't really your concern as a client of the API.> more specifically we want to trigger the "cancel" action
I'd posit that this is actually something that the API user shouldn't need to care about.
Good question though, I've often pondered it myself.
Here is wording from the HTTP spec "However, the server SHOULD NOT indicate success unless, at the time the response is given, it intends to delete the resource or move it to an inaccessible location. "
I don't expect the server to move the booking to an inaccessible location so I see this as a state change not a delete. Hence I am thinking PUT, not DELETE.
/booking/:id
I would go with PUT /booking/:id with a status of canceled.
This makes sense to me because of the semantics of traditional FSM.
You are going from some state (active) to (cancelled). You are not dictating the resulting state, only that you would like to set the status to cancelled.
PUT can return an error in which case the transition failed. It can return success and the transition is good.
States = (active, cancelled);
Transitions = [("cancel", active -> cancelled)]
If the API says PUT status = cancelled, then we'd look through the transitions and find the one that matches our current state and the target state ("cancel"), then execute the associated code, the side effects of this transition - probably sending an email.We now want to refactor the cancellation model to this:
States = (active, cancellation requested, cancelled)
Transitions = [("cancel", active -> cancellation requested),
("confirm", cancellation requested -> cancelled)]
You can see where I'm going with this already, the transition we want the user to take from the active state is the same, but the additional state means that we either have to change the API for cancellation, or have the PUT status do something other than specify the state we're moving to.This is the reason I firmly believe changes of state should be requested by naming the transition, and why I'm not entirely sold on the "best" way to do this with a "proper" RESTful architecture.
POST /booking/:id/cancellation
Because you are creating a 'cancellation object' belonging to that booking.Ninja Edit: Really it is about being consistent, and predictable, so that people using your API can guess how it will act. If you are using an API of yours, and can't guess what the correct url/method is, you should change the API. (I forget who said that)
You are updating the state field (ie UPDATE bookings set status='cancelled' where ID=:id) which maps to PUT
This a thousand times yes.
I might be missing something here though or just not quite understanding the problem.....
It's not a problem for the server (and even then, it might be: what if the root handler simply sends to further sub-handlers after just chopping off part of the URL or query arguments? There isn't necessarily a central URL authority on the servier either), but generally is one for the client: in a truly RESTful system, the client knows one URL and one only (the service's root).
It also knows all the media types the service can return (which is why meaningful content-types, as those returned by Github, are great).
From this, it can traverse the service to the place it needs, and it may cache URLs along the way (for more efficient traversals later on) but those URLs may die altogether and require a re-traversal.
This scenario is built into the architectural style.
> In fact, you need to designate this someplace anyways, whether it's on your server (in the database or in some code), or on the client-side code.
If URLs are designated anywhere in the client-side code (outside of the root service URL and a URL cache, which is accumulated knowledge rather than built-in), it's not a RESTful service, it's RPC-over-HTTP.
But certainly the client needs to know something about the base resources such as product or user? How else will the client know where it can fetch the appropriate resource?
It's definitely still possible to build a RESTful service, but I think if you're primarily building in js, you tend to have more routes that return resources without URLs to other resources than ones that do, especially when you're just starting out and don't have a comprehensive list of resources you want to represent and the accepted mime-types you'd like to be able to return.
Yes, it needs to understand how they're represented, what types of links they might have to other resources, etc.
A good example is the Atom Publishing Protocol (RFC 5023). It's specified entirely in terms of representation formats, resource types, and the actions that can be performed upon those resources.
Of course, that's the "media types" part, it's the complete description/knowledge of a type of resource returned by the service. The media type returned by the service's root is the gateway to the rest of the service. That's the part which is generally missed in RPC-over-URL services claiming to be restful: they exhaustively describe the shape of all the URLs in the system, and then just quickly pass over the media types (the resources at these URLs).
That's doing it literally the wrong way around, a RESTful service documentation should be absolutely exhaustive in its description of the media types, the only "hardcoded" URL of interest to the client is the service root and it only takes a line to specify.
Having worked with both types, the URL type REST is far far easier to write clients for.
I did this in all of my code and it works very well.
1) REST is not suited to complex multi-variable queries or transactions
2) REST should be a stateless transaction
3) REST read results should be cacheable
4) REST can use headers to specify content-type/mime-type
REST is not a suitable replacement for all client-server interactions e.g. complex, sql-like queries over many variables. It is best suited to URL-like queries that produce singleton docs or lists of doc IDs.
REST in its most common form is a protocol over HTTP and thus can (and should) take advantage of HTTP's methods to provide CRUD:
Create = POST
Read = GET
Update = PUT (although POST is fine)
Delete = DELETE
This negates the need for: /story/395/delete
or /delete/story/395
instead use /story/395
and send it a DELETE method.> REST is not suited to complex multi-variable queries or transactions
Would it not be possible to represent a query or transaction as a resource, that you could GET/PUT like any other?
> REST should be a stateless transaction
I think there's a small grey area here around "stateless transaction". The HTTP request/response itself should be atomic (to be a bit loose with terminology), but the result can change the state of the system.
So the communication between client and server is the part of the system that is stateless. (Apologies if this was your intended meaning.)
One of the great advantages of REST is that makes data caching easy. Statelessness is a requirement for caching.
"Would it not be possible to represent a query or transaction as a resource"
Anything's possible just about but the whole point of REST is to create uniform resource locators for data. The problem with creating rather forced complicated URIs is that you quickly lose uniqueness: the same data will start being represented by more than one URI and therefore will start to be cached a multiple of times leading to conflicts.
Also to be REST compliant you have to employ discoverability and hypermedia.
Read: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hyperte... http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm
Using HTTP[S] protocol allows you to pass through almost every heterogeneous network. That means any highly restricted and protected (I prefer the term 'misconfigured') network of a cell phone provider, who blocks everything else, but http.
You can survive in that crazy hotel's or airport's wi-fi network, especially located in developing countries, which is a mess of cheap Chinese ADSL-modems and no-name Wi-Fi access-points with settings no one cares about.
It also means that you can pass through all these almost useless corporate firewalls made by idiots (why firewall if you have all those windows with IE6 boxes running by users with admin rights?).
The second big thing is about statelessness and using URI as a namespace - representing data as a file-system hierarchy and using one standard protocol everywhere - it is almost the same ideas which lays on the foundation of this enlightening Plan9 system. No xml, no BS, just names and simple standard protocol - 9P.
Together, those two ideas are enough to forget about all that proprietary crap, not because it is proprietary, but because REST is more general, flexible and easy to implement concept.
Frankly, I can't believe the amount of near-religious attention it's being given. You're taking an obscure aspect of HTTP (already a mind-bendingly terrible protocol in its own right) - verbs - and making it the cornerstone of your application framework.
Could you detail your thoughts on this? The more I work with HTTP, the more I get impressed with how usable it is. Granted, it's not suited for some domains...
Have you considered some of the hacks that we have to use to make HTTP do what we want? Comet/longpoll? JSONP? Have you looked at the bajillion different ways in which browsers and proxies fail to implement caching in a consistent manner? How browsers will only allow a limited number of concurrent connections to a particular host? Have you looked at a x-www-form-urlencoded post? Do you think that's a good way to send data around?
Anyway, I'm not really after a big discussion of HTTP's merits - my apologies for excessive opinionation. I am, however, interested in why so many people think REST is a magic bullet.
Right, but this sounds like blaming a nail for permanently attaching something when velcro would have been more suitable. Granted, we haven't had many other options, but to me the surprising thing is that HTTP is flexible enough that all of these hacks can be done.
> I am, however, interested in why so many people think REST is a magic bullet.
Human nature? ;)
Well, more accurately, I'm blaming people who think that nails are awesome and the only way to do things - and in fact we should structure all our applications by making use of a relatively obscure aspect of how nails work :)
A slow, unreliable interaction with a remote server is different than an interaction with an in process function call.
If ignoring this complexity is causing no problems then concentrate on what does cause you problems, then just learn enough about REST to recognize a problem in the future.
SOAP v1.0 tunneled everything over POST so you could not cache responses.
A frequent non-restful solution is to return a domain specific id to a client and have the client 'know' that the correct URL is say http://{base}/product/{id}.
The restful solution is to return the URL to the client have them use it what is given rather than construct it. The restful solution allows for many product servers which are independent from the original server. This makes for looser coupling and improved scaling.
REST is essentially what they were thinking, or now think they should have been thinking, when they designed HTTP. So truly honoring the spirit of HTTP gets you close to REST.
But we've known to use GET for operations with no side-effects, and POST for operations that change stuff for many years now, without needing to attach a name to it, throw PUT/DELETE into the mix, or CRUDdifying every operation.
It's the verb part that I really don't get. That, and the general level of excitement surrounding REST. Why are there so damn many articles like this one?
The author of this article has a different understanding of REST than I do. For instance I strongly disagree with this: "One option is not acceptable as a REST response format, except in very specific cases: HTML, or any other format which is meant for human consumption and is not easily processed by clients." I think well marked up HTML is potentially the best response format as long as it is easily understood by clients. And I think this has nothing much to do with REST. Naturally I become motivated to write my own article about REST spelling out how my understanding is is different. Thus the number of articles on REST multiples as a chain reaction until 99.99% of the articles on the internet are about REST. But my 1 year gave me a bad sleep last night dampening the my motivation and saving the world.
In every way, the WWW is a REST-based architecture. REST is an analysis of the web, as it existed at the time. There is no more perfect exemplar of REST.
This is a crucial point. Fielding's paper is about how and why the web works. It's not, per se, about how the web should be used to make network services, though many have tried to derive that from it.
You're right that REST doesn't provide everything SOAP does, because SOAP is a specific protocol and REST is just an architectural style. On the other hand, there are already specific protocols to achieve that in a REST style (and reusing HTTP), like WADL.
Furthermore, it's not clear that a one-size-fits-all approach like SOAP takes is the right way. XML is great for some use cases but not others; by pigeonholing everything to it you create inefficient systems filled with hacks to avoid its shortcomings in certain domains.
SOAP in particular seems very strict, while REST based systems - particularly the Web - are designed to make an heterogeneous mix of decoupled services and clients work well together. The idea that a client should break if the schema changes, for example, leads to very brittle systems.
Thanks for that, much appreciated.
>> The idea that a client should break if the schema changes, for example, leads to very brittle systems.
That's the point, imagine building the web using string values instead of constants. With constants, if it changes, you immediately get notification from the IDE via the compiler and can fix it straight away. If it's a string, then it's up to the poor testers to find it and good luck, it has to be in a known use case.
I think for general communications REST is better than not following any standard by far. For web services though, my money is still on SOAP and I'm a Java/Linux lover not .NET these days, SOAP is still best for Web Services in my view.