Now that I’ve identified the two main questions that web services answer differently, I can group web services by their answers to the questions. In my studies I’ve identified three common web service architectures: RESTful resource-oriented, RPC-style, and REST-RPC hybrid. I’ll cover each in turn.
The main topic of this book is the web service architectures which can be considered RESTful: those which get a good score when judged on the criteria set forth in Roy Fielding’s dissertation. Now, lots of architectures are technically RESTful,but I want to focus on the architectures that are best for web services. So when I talk about RESTful web services, I mean services that look like the Web. I’m calling this kind of service resource-oriented. In Chapter 3 I’ll introduce the basic concepts of resource-oriented REST, in the context of a real web service: Amazon’s Simple Storage Service. Starting in Chapter 4, I’ll talk you through the defining characteristics of REST, and define a good architecture for RESTful web services: the Resource-Oriented Architecture.
In RESTful architectures, the method information goes into the HTTP method. In resource-oriented architectures, the scoping information goes into the URI. The combination is powerful. Given the first line of an HTTP request to a resource-oriented RESTful web service (“GET /reports/open-bugs HTTP/1.1”), you should understand basically what the client wants to do. The rest of the request is just details; indeed, you can make many requests using only one line of HTTP. If the HTTP method doesn’t match the method information, the service isn’t RESTful. If the scoping information isn’t in the URI, the service isn’t resource-oriented. These aren’t the only requirements, but they’re good rules of thumb.
A few well-known examples of RESTful, resource-oriented web services include:
Whenever I cover unRESTful architectures, as well as architectures that aren’t resource-oriented, I do it with some ulterior motive. In this chapter, I want to put RESTful web services into perspective, against the larger backdrop of the programmable web. In Chapter 2, I’m widening the book’s coverage of real web services, and showing that you can use the same client tools whether or not a service exactly fits my preferred architecture. In Chapter 10, I’m making an argument in a long-running debate about what the programmable web should look like.
An RPC-style web service accepts an envelope full of data from its client, and sends a similar envelope back. The method and the scoping information are kept inside the envelope, or on stickers applied to the envelope. What kind of envelope is not important to my classification, but HTTP is a popular envelope format, since any web service worthy of the name must use HTTP anyway. SOAP is another popular envelope format (transmitting a SOAP document over HTTP puts the SOAP envelope inside an HTTP envelope). Every RPC-style service defines a brand new vocabulary. Computer programs work this way as well: every time you write a program, you define functions with different names. By contrast, all RESTful web services share a standard vocabulary of HTTP methods. Every object in a RESTful service responds to the same basic interface.
The XML-RPC protocol for web services is the most obvious example of the RPC architecture. XML-RPC is mostly a legacy protocol these days, but I’m going to start off with it because it’s relatively simple and easy to explain. Example 1-11 shows a Ruby client for an XML-RPC service that lets you look up anything with a Universal Product Code.
Example 1-11. An XML-RPC example: looking up a product by UPC
#!/usr/bin/ruby -w # xmlrpc-upc.rb require 'xmlrpc/client' def find_product(upc) server = XMLRPC::Client.new2('http://www.upcdatabase.com/rpc') begin response = server.call('lookupUPC', upc) rescue XMLRPC::FaultException => e puts "Error: " puts e.faultCode puts e.faultString end end puts find_product("001441000055")['description'] # "Trader Joe's Thai Rice Noodles"
An XML-RPC service models a programming language like C. You
call a function (
some arguments (“001441000055”) and get a return value back. The
method data (the function name) and the scoping data (the arguments)
are put inside an XML document. Example 1-12
gives a sample document.
Example 1-12. An XML document describing an XML-RPC request
<?xml version="1.0" ?> <methodCall> <methodName>lookupUPC</methodName> <params> <param><value><string>001441000055</string></value></param> </params> </methodCall>
This XML document is put into an envelope for transfer to the server. The envelope is an HTTP request with a method, URI, and headers (see Example 1-13). The XML document becomes the entity-body inside the HTTP envelope.
Example 1-13. An HTTP envelope that contains an XML document which describes an XML-RPC request
POST /rpc HTTP/1.1 Host: www.upcdatabase.com User-Agent: XMLRPC::Client (Ruby 1.8.4) Content-Type: text/xml; charset=utf-8 Content-Length: 158 Connection: keep-alive <?xml version="1.0" ?> <methodCall> <methodName>lookupUPC</methodName> ... </methodCall>
The XML document changes depending on which method you’re calling, but the HTTP envelope is always the same. No matter what you do with the UPC database service, the URI is always http://www.upcdatabase.com/rpc and the HTTP method is always POST. Simply put, an XML-RPC service ignores most features of HTTP. It exposes only one URI (the “endpoint”), and supports only one method on that URI (POST).
Where a RESTful service would expose different URIs for different values of the scoping information, an RPC-style service typically exposes a URI for each “document processor”: something that can open the envelopes and transform them into software commands. For purposes of comparison, Example 1-14 shows what that code might look like if the UPC database were a RESTful web service.
Example 1-14. A hypothetical code sample: a RESTful UPC lookup service
require 'open-uri' upc_data = open('http://www.upcdatabase.com/upc/00598491').read() ...
Here, the method information is contained in the HTTP method.
The default HTTP method is GET, which is equivalent in this scenario
lookupUPC. The scoping
information is contained in the URI. The hypothetical service exposes
an enormous number of URIs: one for every possible UPC. By contrast,
the HTTP envelope is empty: an HTTP GET request contains no
entity-body at all.
For another example of a client for an RPC-style service, look back at Example 1-8. Google’s SOAP search API is an RPC-style service that uses SOAP as its envelope format.
A service that uses HTTP POST heavily or exclusively is probably an RPC-style service. Again, this isn’t a sure sign, but it’s a tip-off that the service isn’t very interested in putting its method information in the HTTP method. An otherwise RESTful service that uses HTTP POST a lot tends to move toward a REST-RPC hybrid architecture.
A few well-known examples of RPC-style web services:
All services that use XML-RPC
Just about every SOAP service (see the Technologies on the Programmable Web” section later in this chapter for a defense of this controversial statement)
A few web applications (generally poorly designed ones)
This is a term I made up for describing web services that fit somewhere in between the RESTful web services and the purely RPC-style services. These services are often created by programmers who know a lot about real-world web applications, but not much about the theory of REST.
Take another look at this URI used by the Flickr web service: http://www.flickr.com/services/rest?api_key=xxx&method=flickr.photos.search&tags=penguin. Despite the “rest” in the URI, this was clearly designed as an RPC-style service, one that uses HTTP as its envelope format. It’s got the scoping information (“photos tagged ‘penguin’”) in the URI, just like a RESTful resource-oriented service. But the method information (“search for photos”) also goes in the URI. In a RESTful service, the method information would go into the HTTP method (GET), and whatever was leftover would become scoping information. As it is, this service is simply using HTTP as an envelope format, sticking the method and scoping information wherever it pleases. This is an RPC-style service. Case closed.
Except…look at Example 1-15.
Example 1-15. A sample HTTP request to the Flickr web service
GET services/rest?api_key=xxx&method=flickr.photos.search&tags=penguin HTTP/1.1 Host: www.flickr.com
That’s the HTTP request a client makes when remotely calling this procedure. Now it looks like the method information is in the HTTP method. I’m sending a GET request to get something. What am I getting? A list of search results for photos tagged “penguin.” What used to look like method information (“photoSearch()”) now looks like scoping information (“photos/tag/penguin”). Now the web service looks RESTful.
This optical illusion happens when an RPC-style service uses plain old HTTP as its envelope format, and when both the method and the scoping information happen to live in the URI portion of the HTTP request. If the HTTP method is GET, and the point of the web service request is to “get” information, it’s hard to tell whether the method information is in the HTTP method or in the URI. Look at the HTTP requests that go across the wire and you see the requests you’d see for a RESTful web service. They may contain elements like “method=flickr.photos.search” but that could be interpreted as scoping information, the way “photos/” and “search/” are scoping information. These RPC-style services have elements of RESTful web services, more or less by accident. They’re only using HTTP as a convenient envelope format, but they’re using it in a way that overlaps with what a RESTful service might do.
Many read-only web services qualify as entirely RESTful and resource-oriented, even though they were designed in the RPC style! But if the service allows clients to write to the data set, there will be times when the client uses an HTTP method that doesn’t match up with the true method information. This keeps the service from being as RESTful as it could be. Services like these are the ones I consider to be REST-RPC hybrids.
Here’s one example. The Flickr web API asks clients to use HTTP
GET even when they want to modify the data set. To delete a photo you
make a GET request to a URI that includes
method=flickr.photos.delete. That’s just not
what GET is for, as I’ll show in Chapter 5. The
Flickr web API is a REST-RPC hybrid: RESTful when the client is
retrieving data through GET, RPC-style when the client is modifying
the data set.
A few well-known examples of REST-RPC hybrid services include:
The del.icio.us API
The “REST” Flickr web API
Many other allegedly RESTful web services
Most web applications
From a design standpoint, I don’t think anybody sets out to to design a service as a REST-RPC hybrid. Because of the way HTTP works, any RPC-style service that uses plain HTTP and exposes multiple URIs tends to end up either RESTful or hybrid. Many programmers design web services exactly as they’d design web applications, and end up with hybrid services.
The existence of hybrid architectures has caused a lot of confusion. The style comes naturally to people who’ve designed web applications, and it’s often claimed that hybrid architectures are RESTful: after all, they work “the same way” as the human web. A lot of time has been spent trying to distinguish RESTful web services from these mysterious others. My classification of the “others” as REST-RPC hybrids is just the latest in a long line of neologisms. I think this particular neologism is the most accurate and useful way to look at these common but baffling services. If you’ve encountered other ways of describing them (“HTTP+POX” is the most popular at the time of writing), you might want read on, where I explain those other phrases in terms of what I’m saying in this book.
In the previous sections I claimed that all static web sites are RESTful. I claimed that web applications fall into one of the three categories, the majority being REST-RPC hybrids. Since the human web is made entirely of static web sites and web applications, this means that the entire human web is also on the programmable web! By now this should not be surprising to you. A web browser is a software program that makes HTTP requests and processes the responses somehow (by showing them to a human). That’s exactly what a web service client is. If it’s on the Web, it’s a web service.
My goal in this book is not to make the programmable web bigger. That’s almost impossible: the programmable web already encompasses nearly everything with an HTTP interface. My goal is to help make the programmable web better: more uniform, better-structured, and using the features of HTTP to greatest advantage.
 More than you’d think. The Google SOAP API for web search technically has a RESTful architecture. So do many other read-only SOAP and XML-RPC services. But these are bad architectures for web services, because they look nothing like the Web.