Skip to main content

Books: RESTful Web Services

I just finished reading RESTful Web Services. I'll summarize. At its worst, it was boring and dogmatic. At its best, it helped me to formalize my understanding of REST, and it gave me a protocol-level introduction to a variety of topics like the Atom Publishing Protocol, microformats, S3, del.icio.us, HTML 5, etc.

One thing I found particularly frustrating is the author's attitude toward RPC. Basically, his stance is that RPC is synonymous with all things evil. Consider the following quote:
This is why making up your own HTTP methods is a very, very bad idea: your custom vocabulary puts you in a community of one. You might as well be using XML-RPC. [p. 105]
Ok, so using XML-RPC is just as bad as sending "EAT / HTTP/1.0" to a server. WTF?

I've implemented services using CORBA, JRMI, XML-RPC, and a couple times with REST. At the risk of calling the emperor naked, I liked XML-RPC the most. REST might look nicer at the wire level, but at least in Python, XML-RPC is a heck of a lot easier to code for. None of the author's client examples can match the simplicity of using an XML-RPC service in Python. Sure, you can say that XML is ugly, but I never actually had to deal with XML when using XML-RPC. The libraries did it for me. However with REST, I have to slog through XML all the time.

Another thing that frustrated me about this book was how often it relies on standards that aren't yet standard. The back of the book says, 'This book puts the "Web" back into web services.' Unfortunately, this book makes use of HTML 5, a couple different IETF Internet-Drafts, and HTTP methods that my browser doesn't actually support. It should have said, "This book shows you how great REST would be if we had the perfect web."

One thing I really liked about this book was the checklist for creating Resource-Oriented Architectures, which I'll quote here:
  1. Figure out the data set.
  2. Split the data set into resources.
  3. For each kind of resource:
    1. Name the resources with URIs
    2. Expose a subset of the uniform interface
    3. Design the representation(s) accepted from the client
    4. Design the representation(s) served to the client.
    5. Integrate this resource into existing resources, using hypermedia links and forms.
    6. Consider the typical course of events: what's supposed to happen? Standard control flows like the Atom Publishing Protocol can help (see Chapter 9).
    7. Consider error conditions: what might go wrong? Again, standard control flows can help. [p. 216]
Aside from that, here is a list of quotes that I found surprising, frustrating, interesting, or simply entertaining (especially when taken out of context):
Now, lots of architectures are technically RESTful...More than you'd think. The Google SOAP API for web search technically has a RESTful architecture...But these are bad architectures for web services, because they look nothing like the Web. [p. 13]
Service-Oriented Architecture...This is a big industry buzzword...A book on service-oriented architecture should work on a slightly higher level, showing how to use services as software components, how to integrate them into a coherent whole. I don't cover that sort of thing in this book. [p. 20]
ProgrammableWeb...is the most popular web service directory...Its terminology isn't as exact as I'd like (it tends to classify REST-RPC hybrids as "REST" services). [p. 368]
I do my bit to promote WADL as a resource-oriented alternative to WSDL. I think it's the simplest and most elegant solution. [p. 25]
If a web service designer has never heard of REST, or thinks that hybrid services are "RESTful," there's little you can do about it. Most existing services are hybrids or full-blown RPC services. [p. 27]
Another uniform interface consists solely of HTTP GET and overloaded POST...This interface is perfectly RESTful, but, again, it doesn't conform to my Resource-Oriented Architecture. [p. 125]
Web services are just web sites for robots. [p. 132]
I need to truly capture the capabilities of my service. XHTML 5 has a feature called the repetition model, which allows me to express an arbitrary number of text boxes without writing an infinitely long HTML page. [p. 136]
You may have noticed a problem in Example 6-3. Its form specifies an HTTP method of PUT...I'm using the as-yet-unreleased XHTML 5 to get around the shortcomings of the current version of HTML. [p. 153]
The two derivations from the HTML you're familiar with are in the method attribute...and the brand-new template attribute, which inserts a form variable ("username") into the URI using the URI Templating standard (http://www.ietf.org/internet-drafts/draft-gregorio-uritemplate-00.txt). [p. 155]
Note that the Internet-Draft itself says:
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."
I had to hack Rails to get the behavior I want, instead of the behavior Rails creator David Heinemeier Hansson wants. [p. 168]
It's been a while since I presented any code. Indeed, coming up with the code is currently a general problem for REST advocates. [p. 167]
There's no good way to do that in Rails. [p. 189]
The if_found method sends a response code of 404 ("Not Found") if the user tries to GET or DELETE a nonexistent user. [p. 199; Hey, I thought DELETE was supposed to be idempotent!]
Of course, using the web service just means writing more code. [p. 209]
Clients could work on a higher level than HTTP...The idea here is to apply higher-level conventions than REST's, so that the client programmer doesn't have to write as much code. [p. 212]
The ActiveResource/ActiveRecord approach won't work for all web services, or even all Rails web services. It doesn't work very well on this service...As of the time of writing, it's more a promising possibility than a real-world solution to a problem. [p. 212]
If you want to do without PUT and DELETE altogether, it's entirely RESTful to expose safe operations on resources through GET, and all other operations through overloaded POST. Doing this violates my Resource-Oriented Architecture, but it conforms to the less restrictive rules of REST. [p. 220]
But every resource works basically the same way and can be acccessed with a universal client. This is a big part of the success of the Web. The restrictions imposed by the uniform interface (safety for GET and HEAD, idempotence for PUT and DELETE) make HTTP more reliable. [p. 222; The web was successful despite the fact that GET is often not safe and PUT and DELETE aren't available in Web browsers.]
How can you DELETE two resources at once?...You might be wondering what HTTP status code to send in response to a batch operation...You can use an extended HTTP status code created by the WebDAV extension to HTTP: 207 ("Multi-Status"). [p. 230]
Yet again, the way to deal with an action that doesn't fit the uniform interface is to expose the action itself as a resource. [p. 232]
I'll translate. If you feel the need to use verbs other than GET, PUT, POST, and DELETE, just convert your verb to a noun. REST consists of converting all interesting verbs into nouns so that you only have to use basic verbs like GET, PUT, POST, DELETE, HEAD, and OPTIONS.
[Browsers only support GET and POST.] If the server supports it, a client can get around these limitations by tunneling PUT and DELETE requests through overloaded POST...Include the "real" HTTP method in the query string. Ruby on Rails defines a hidden form field called _method...Restlet uses the method variable...The second way is to include the "real" HTTP action in the X-HTTP-Method-Override HTTP request header. [p. 252; That's a pretty good summary of how to stick to the web's uniform interface.]
A web service that sends HTTP cookies violates the principle of statelessness...What about cookies that really do contain application state? What if you serialize the actual session hash and send it as a cookie...This can be RESTful, but it's usually not. [p. 252]
POST Once Exactly (POE) is a way of making HTTP POST idempotent, like PUT and DELETE...Post was defined by Mark Nottingham in an IETF draft that expired in 2005. [p. 283; He is relying on a long-expired Internet-Draft to show how to implement a feature.]
I cover four hypermedia technologies in this section. As of the time of writing, XHTML 4 is the only hypermedia technology in active use. [p. 285]
As of the time of writing, WADL is more talked about than used. [p. 290]
If all you're doing is serializing a data structure for transport across the wire (as happens in the weblogs.com ping service), consider JSON as your representation format. [p. 308]
In 2006, IBM and Microsoft shut down their public UDDI registry after publicly declaring it a success. [p. 309]
Suffice it to say that security concepts are much better specified and deployed in SOAP-based protocols than in native HTTP protocols. [p. 311; Which isn't to say I like SOAP.]
Two-phase commit requires a level of control over and trust in the services you're coordinating. This works well when all the services are yours, but not so well when you need to work with a competing bank...I generally think it's inappropriate for RESTful web services. [p. 313]
Refer [is a] request header...Yes, it's misspelled. [p. 401; That would explain why I always misspell it!]
Anyway, sorry for going so long. I hope some of those quotes entertained you as much as they entertained me.

Comments

Steve Vinoski said…
Leonard and Sam are definitely right about the evils of RPC. For more information you might want to read my July/August 2008 Internet Computing column entitled Convenience over Correctness. The fact that you mention that you like XML-RPC because it's the most convenient fits perfectly into the topic my column discusses. My other columns about REST from earlier in 2008, available from the same site, might also interest you.
Anonymous said…
Hi Shannon,

You have written an interesting sentence in your book review.

>HTTP methods that my browser doesn't actually support.

The Web doesn't work only with browsers and it's what the book is showing, that you can use and define clients using all verbs of HTTP. The Verbs in HTTP are a collection of tools to manage information. Here I'm not talking about code at all :)

I didn't find XML-RPC easier to use in Python than pure HTTP, quite the opposite in fact. I don't think the book is really against XML-RPC, but more a big warning about why XML-RPC removes often the Web nature of an application.

It is like Web format. An XML format is not a Web format if it doesn't have a linking capabilities (hypertext).

The review is quite interesting. I have a tendency to agree that sometimes the book is missing the target, but nothing is perfect.

--
Karl
dowski.com said…
Nice writeup. I agree that XML-RPC is drop-dead simple to use in Python.

Regarding your comment on the idempotent nature of DELETE ...

"The if_found method sends a response code of 404 ("Not Found") if the user tries to GET or DELETE a nonexistent user. [p. 199; Hey, I thought DELETE was supposed to be idempotent!]"

I think DELETE is still considered idempotent if the first request returns "200 OK" and subsequent requests return "404 Not Found". The spec uses the term idempotent in terms of the side effects of the request, not the status code returned. So it is a bit of a non-standard use of the term, I suppose.

9.1.2 Idempotent Methods

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
elarson said…
One aspect of RESTful services that I found lacking in the book is the association between a document and hypertext. Often times the examples were using XML, but using JSON makes things much easier while still allowing hypertext for reducing the reliance on things like cookies for state.

The main advantage of REST is the ability to focus on the document instead of the data. This allows anyone else to use the skills they have for basic document managment (for line in open('some_file.txt')) to effectively use the service. This is a huge plus, but as you mention, requires more work.

Also, I've found that REST makes more sense when considering a Public service. For example, we use Pyro where I work and it is really fast and simple. Yet, it we were to have a public service, I'd imagine we'd consider a more RESTful solution.

In any case, I liked your review as it suggests that "Restafarians" (which I do consider myself) be realistic when touting the advantages of REST.
> Convenience Over Correctness

Ok, I've read it. Thanks for your comment.

I agree with many of your comments concerning RPC. I also agree that REST has real benefits (such as caching and proxy support) that aren't present (to my knowledge) in XML-RPC.

I think some of your complaints about RPC don't apply as much to XML-RPC. Because XML-RPC doesn't support passing "objects" over the wire, you can't simply ignore the fact that the message call is remote. When you use XML-RPC, you should be aware that it's not local. That's just common sense to me.

I don't think that because REST is harder to use means we'll be smarter about using it. I think that's like saying that because Java forces you to write type declarations all over the place, you're more likely to write good code. In practice, you can do stupid things with both Java and REST.

You said, "Many developers are attracted to REST, but unsurprisingly, some try to build programming language frameworks to make it convenient." I think you and I agree on this one, and we both disagree with the book. The book tries hard to write client code that hides the remote server. To me, the book is trying hard to make REST look as convenient as RPC, while often ignoring all the complexity you bring up in your article.

That flies in the face of your stance that the caller *should know* that he's calling a remote function. It shouldn't *feel* like a native function call. You and I agree that Erlang's mechanism is nice in this regard. I like asynchronous programming too.
> I think DELETE is still considered idempotent if the first request returns "200 OK" and subsequent requests return "404 Not Found". The spec uses the term idempotent in terms of the side effects of the request, not the status code returned. So it is a bit of a non-standard use of the term, I suppose.

Great comment. Thanks.
Steve Vinoski said…
Thanks for your comments on my article, much appreciated.

I disagree with your assessment of XML-RPC, though, as it is in fact one of the best examples of convenience over correctness ever conceived. It ignores the fact that HTTP is an application protocol and treats it instead as a transport protocol, tunneling everything through POST. The HTTP POST method is non-idempotent, which means that when something goes wrong, the client has to have special knowledge of the server to know whether or not it can retry the operation. Whether or not it deals with objects or not is irrelevant; XML-RPC effectively builds a specialized protocol for each server which it forces through POST, and that specialization means a significant amount of coupling between client and server. It ignores GET and other aspects of the HTTP application protocol and therefore misses out on important scalability and loose coupling features. It's like the worst of all worlds, created solely to allow RPC-oriented programming to take place easily over HTTP.

I didn't get the impression that Leonard and Sam tried in their book to ignore the complexities that distribution brings. That thought never occurred to me as I read the book, and I'm pretty sure I would have noticed that. The important point here is again that HTTP is an application protocol, and I know Leonard and Sam fully understand the implications of that. It means that used correctly, HTTP becomes part of the application itself rather than being relegated to a convenient layer stuck below the application attempting to hide distribution effects ala RPC. In other words, correct HTTP applications explicitly use HTTP features in order to gain the many benefits of the protocol, and don't try to paper over it or hide it the way XML-RPC and WS-* do. This correct usage of HTTP is precisely what I saw in the book.
> I disagree with your assessment of XML-RPC, though, as it is in fact one of the best examples of convenience over correctness ever conceived. It ignores the fact that HTTP is an application protocol and treats it instead as a transport protocol, tunneling everything through POST.

Agreed.

> The HTTP POST method is non-idempotent, which means that when something goes wrong, the client has to have special knowledge of the server to know whether or not it can retry the operation.

Agreed.

> Whether or not it deals with objects or not is irrelevant;

Dealing with objects adds quite a lot of complexity. That's why XML-RPC is much simpler than Corba or SOAP, so I'm going to disagree.

> XML-RPC effectively builds a specialized protocol for each server which it forces through POST, and that specialization means a significant amount of coupling between client and server.

Correct. I think this is a matter of engineering taste. The coupling is lose enough that the client and server can be written in different languages, but it's not so lose that one client can talk to multiple servers. For my uses, I'm okay with that.

> It ignores GET and other aspects of the HTTP application protocol and therefore misses out on important scalability and loose coupling features.

Agreed.

> It's like the worst of all worlds,

It's got some good points and some bad points.

> created solely to allow RPC-oriented programming to take place easily over HTTP.

Agreed.

> I didn't get the impression that Leonard and Sam tried in their book to ignore the complexities that distribution brings. That thought never occurred to me as I read the book, and I'm pretty sure I would have noticed that.

Take a peek at when they were writing the client driver for S3. I'm not sure, but perhaps that will change your opinion.

> The important point here is again that HTTP is an application protocol, and I know Leonard and Sam fully understand the implications of that. It means that used correctly, HTTP becomes part of the application itself rather than being relegated to a convenient layer stuck below the application attempting to hide distribution effects ala RPC.

I understand that.

> In other words, correct HTTP applications explicitly use HTTP features in order to gain the many benefits of the protocol, and don't try to paper over it or hide it the way XML-RPC and WS-* do.

I understand that too.

> This correct usage of HTTP is precisely what I saw in the book.

I don't disagree with that.

I think my main points are:

0) I agree with the benefits of rest.

1) The book is a bit on the dogmatic side.

2) For all its flaws, XML-RPC was easy--as your own paper suggests.

3) I'm getting the feeling that writing client drivers for RESTful services is just busy work.

4) I have the feeling that using REST could be made even simpler. I'm talking about syntactic convenience and boilerplate reduction.

Thanks for your great comments :)
Evans said…
Nice review! After reading your review I decided to get a copy. Unfortunately, as a Java Developer, I found it rather out of my area.

Its more about Ruby and Python and little or no Java examples in the book. Good book nonetheless.

Nice blog by the way
> Its more about Ruby and Python and little or no Java examples in the book. Good book nonetheless.

Did you read the section on how to develop RESTful Web applications in Java? A whole app is built.

> Nice blog by the way

Thanks!