What it is not
Too often I have heard the term REST used in a wrong way. Sometimes people think that when they are accessing a Web Service via a simple HTTP GET and the URL, they are using REST.
For example I’ve seen stuff like this in the Axis2 documentation, where they say, that you invoke a deployed SOAP service the REST way by using your browser and navigating to a certain URL:
http://domain.com/service-name/service-method?parameter=value
This is not RESTful!
So a lot of times you can see services claiming having a REST interface, when in reality they only have a HTTP GET interface, which totally misses the point. (Don’t get me wrong here, Axis2 actually seems to have real REST support, but the above example is not part of that!)
Okay, so what is REST then?
REST uses the HTTP architecture and (usually) XML, which are basically used everywhere. It does not add a new protocol layer (like the SOAP envelope for example) on top of that. Unlike SOAP, you don’t define services with actions (methods) and arguments.
Instead it’s all about resources and representations. All resources can be listed, viewed, created, updated or deleted. And every resource has at least one representation (think of it as rendering the raw data), for example in XML, HTML or Plaintext.
It is best described using an example:
A bookstore example
Say we have a bookstore where we want to publish books and let authors upload their own books.
So what we need to do is create, read, update and delete books. (Note the 4 verbs and the noun books in there) This is basically what all RESTful web services do: basic CRUDing. That’s also what databases do by the way in addition to allowing complex search queries.
The nice thing now is that HTTP already supports keywords for exactly these use cases. I guess you all know GET and POST requests. But there are also some other verbs defined like PUT and DELETE for example.
Listing all items
Listing resources is usually the first step for a user of the REST service to get an overview of what’s available. It is similar to viewing the items, but instead it returns all resources of a certain type. To list all books of our store we simple send a GET request to the following URL:
http://domain.com/books
This will return a list of <book> elements in the HTTP response body, like this:
<books>
<book>
<id>1</id>
<title>Cryptonomicon</title>
<author>Neal Stephenson</author>
<price>19.95</price>
</book>
</books>
Currently there is only one book, let’s upload a new one.
Creating resources
To upload a book, we POST to the very same URL. The nice thing about REST is, that we reuse URLs (resources) all over again, we just change the verb to tell the service what we want to do with it. So just send a POST request to the books resource:
http://domain.com/books
As you can see there are no parameters supplied in the URL, the actual payload is in the HTTP request body, like this:
<book>
<title>World War Z</title>
<author>Max Brooks</author>
<price>14.95</price>
</book>
Note that there’s no id-parameter supplied yet, as this is not needed, because the web service will create one when it actually stores the book in its database backend. (You as the web service author are responsible for doing this, Rails does it automatically)
Now what do we do if we want to update the price of a book? Let’s use 2 steps for that, to see a real world use case, and also learn some theory and vocabulary.
Representations
Your data is usually saved in a (relational) database. But your users need a certain view (a.k.a. representation) of this raw data. And you can represent your data not only as XML, but also as HTML, JSON, CSV or whatever format you need. If you want you can also support multiple formats, and let your users decide which representation of the data they want to see.
For this HTTP has the content-type header, which you would set to application/xml to get your book in XML as we need to do in our examples. (Note: We needed to send this content-type for every request so far, but I haven’t mentioned it yet, to keep it simple at the beginning.)
Show me a resource
To get a book with the ID 2, we send a GET request with the content-type header of application/xml to the following URL:
http://domain.com/books/2
Note: We could also identify our books via something more descriptive, e.g. their title, but then we have to make sure that a) each title is unique and b) the id-part of the URL is all lowercase and uses dashes instead of spaces (this is not absolutely needed, but makes the URLs much easier to read – it’s really confusing to use mixed case in URLs for the end user). An example URL for the above book would be:
http://domain.com/books/world-war-z
Modifying the Show view
In any way we get the following XML back, which is basically the same we uploaded before, but with an additional ID field, which was inserted by our backend. (Note: If we would use the title as our ID, then obviously this field is not present)
<book>
<id>2</id>
<title>World War Z</title>
<author>Max Brooks</author>
<price>14.95</price>
</book>
So lets say, we want to increase the price of the book, because it’s so good. We just set the text of the <price> element (with our XML library of choice or a simple String-replace) to our new value.
Updating a resource
Now that we have the updated XML representation of the book, we are ready to upload it to the server. REST uses the HTTP method PUT for updating.
Just send a PUT request (with the XML payload in the http-body) to the URL of this resource:
http://domain.com/books/2
If everything went well, the server should send a HTTP status code of 200 (OK) or 201 (Created). The nice thing is that HTTP already defines all the status codes you need, so no need to reinvent the wheel. And you can always send additional status messages in the body of the response.
Delete with DELETE
So you think this was easy? (I hope so) Then wait till you see how we remove resources. There is a HTTP method for exactly this use case, which was not really used before REST. Just send a DELETE request to the target resource:
http://domain.com/books/2
There you have it, same URL again, different method.
Summary
That is the basic architecture of a REST based web service. Basically you send one of the four HTTP request methods to a URL and put any payload directly in the HTTP body. The server sends a response with an appropriate HTTP status code and also puts any content in the body.
Advanced uses
Let’s say you also want to view certain chapters of a book. Usually you would think of something like this:
http://domain.com/books/2?chapter=1
This is also the way Axis2 handles arguments to a service’s method. But doesn’t it look way better the following way:
http://domain.com/books/2/chapters/1
This is the concept of nested resources. You have a full URL (without any URL parameters) that identifies a given resource. It gets even clearer when you have an even deeper nesting than two. Let’s say we also want to view certain pages of a chapter. Compare the following:
http://domain.com/books/2?chapter=1&page=2
This doesn’t make clear if we mean the 2nd page of the book or the 2nd page of a chapter. With nested resources it’s unambiguous:
http://domain.com/books/2/chapters/1/pages/2
It should be clear, that this returns the 2nd page of the 1st chapter of the 2nd book. Note that we always used the plural version of a resource. This allows us to GET a list of all chapters using the URL:
http://domain.com/books/2/chapters
And it also allows us to POST new chapters to the very same URL!
Advantages of the REST approach
First of all I think it’s really simple (you need to have a basic understanding of HTTP though – which every web developer should have anyways). And you are reusing existing technology, instead of adding even more to the already crowded IT world. For example you can use HTTPS in combination with HTTP basic authentication for security.
Because SOAs often forward messages and act as middleware, you can make use of the lightweight HTTP redirection and referrer mechanisms.
All REST services have a uniform interface. Unlike SOAP you don’t really need a WSDL to see what methods are available for your service: if you know which resources are available, you know that you can GET, POST, PUT or DELETE them.
REST services can be invoked by the browser. When you have HTML representations, you can GET them with the browser, and you can also POST resources (e.g. as JSON). Unfortunately current browsers do not support PUT and DELETE requests from HTML forms (maybe Firefox3 does, not sure?), but I’m sure we will see these in the future.
Disadvantages
As REST uses the CRUD approach, it is sometimes not easy to implement certain service designs. For example a calculator in SOAP style would have add() and multiply() methods with 2 (or more) arguments.
In REST you have to rely on the GET, POST, PUT and DELETE methods, so at first this problem might seem untackable. But with a different way of thinking, it could be realized like this: You have sum and product resource, which you will GET for different arguments, for example:
http://domain.com/calculator/sum/1/2
Which simply return 3 in the body. You could always use dynamic number of arguments like the following:
http://domain.com/calculator/product/1/2/3/4
And this would return 24 and a status code of 200 (ok).
Additional Reading
There’s a lot more to REST than I could cover in one mere article (for example caching). Whole books can be written about RESTful design (somehow I know only one). To get started here are some links I found helpful:
- How I explained REST to my wife (Simple words, but yet helpful for the big picture)
- The original dissertation by Roy Fielding (Who defined the term REST)
- RESTful Rails development (A short and free ebook showing Rails’ REST support)
- Wikipedia article about REST (Interesting read and a whole bunch of more links)
“Unfortunately current browsers do not support PUT and DELETE requests from HTML forms (maybe Firefox3 does, not sure?), but I’m sure we will see these in the future.”
Doesn’t this fact completely undermine the advantages of REST for end-user-facing websites? If no modern web browsers support it [yet], what is a web developer to do (besides not make his/her site RESTful)? It’s like saying “these roads are really efficient to drive on as long as your vehicle has 7 wheels” — except nearly all users’ vehicles are 2- or 4-wheeled.
@Pistos
The thing is that invoking web services via the browser (especially to delete and update stuff) is not a very common use case. You can invoke these requests via Javascript (with the XMLHTTPRequest) though to get around that.
And you can always use tricks like Rails does: insert a hidden field in the form with the method parameter named “method” and set that to “put” or “delete” and configure your web service to check that parameter before dispatching the request to the right action. (Not pretty but it totally works and doesn’t require any work if you use Rails)
Interesting, I will have to investigate this further.
Oh, and “Hi!”
@soleone
Those tricks you mentioned mean it’s not REST, as the article says it it’s first paragraph, it’s then a GET (or POST) interface and not REST at all
@Clive Crous
The thing is that the calculator example is a read-only service. It doesn’t really make sense to Update, Create or Delete anything in this simple calculator. All you want is to GET the result of a calculation!
But you have a point, maybe I was to quick to judge the Axis2 method invocation style as not RESTful at all. Although the URLs they use are not pretty, it still uniquely qualifies a resource, which is a cornerstone of REST. And after all with SOAP you’re only interested in calling a method, so maybe it makes sense to GET the result of the method invocation.
But POSTing to the service still seems like a violation of the REST principles as using a POST indicates creating something on the server.
The real problem here is that SOAP is not modeled as a CRUD service (it’s just remote method invocation), so there can be no full fledged generic RESTful interface on top of it to access it.