Addressability is one of the four main features of the ROA. The second is statelessness. I’ll give you two definitions of statelessness: a somewhat general definition and a more practical definition geared toward the ROA.
Statelessness means that every HTTP request happens in complete isolation. When the client makes an HTTP request, it includes all information necessary for the server to fulfill that request. The server never relies on information from previous requests. If that information was important, the client would have sent it again in this request.
More practically, consider statelessness in terms of addressability. Addressability says that every interesting piece of information the server can provide should be exposed as a resource, and given its own URI. Statelessness says that the possible states of the server are also resources, and should be given their own URIs. The client should not have to coax the server into a certain state to make it receptive to a certain request.
On the human web, you often run into situations where your browser’s back button doesn’t work correctly, and you can’t go back and forth in your browser history. Sometimes this is because you performed an irrevocable action, like posting a weblog entry or buying a book, but often it’s because you’re at a web site that violates the principle of statelessness. Such a site expects you to make requests in a certain order: A, B, then C. It gets confused when you make request B a second time instead of moving on to request C.
Let’s take the search example again. A search engine is a web service with an infinite number of possible states: at least one for every string you might search for. Each state has its own URI. You can ask the service for a directory of resources about mice: http://www.google.com/search?q=mice. You can ask for a directory of resources about jellyfish: http://www.google.com/search?q=jellyfish. If you’re not comfortable creating a URI from scratch, you can ask the service for a form to fill out: http://www.google.com/.
When you ask for a directory of resources about mice or jellyfish, you don’t get the whole directory. You get a single page of the directory: a list of the 10 or so items the search engine considers the best matches for your query. To get more of the directory you must make more HTTP requests. The second and subsequent pages are distinct states of the application, and they need to have their own URIs: something like http://www.google.com/search?q=jellyfish&start=10. As with any addressable resource, you can transmit that state of the application to someone else, cache it, or bookmark it and come back to it later.
Figure 4-1 is a simple state diagram showing how an HTTP client might interact with four states of a search engine.
This is a stateless application because every time the client makes a request, it ends up back where it started. Each request is totally disconnected from the others. The client can make requests for these resources any number of times, in any order. It can request page 2 of “mice” before requesting page 1 (or not request page 1 at all), and the server won’t care.
By way of contrast, Figure 4-2 shows the same states arranged statefully, with states leading sensibly into each other. Most desktop applications are designed this way.
That’s a lot better organized, and if HTTP were designed to allow
stateful interaction, HTTP requests could be a lot simpler. When the
client started a session with the search engine it could be
automatically fed the search form. It wouldn’t have to send any request
data at all, because the first response would be predetermined. If the
client was looking at the first 10 entries in the mice directory and
wanted to see entries 11–20, it could just send a request that said
“start=10”. It wouldn’t have to send
/search?q=mice&start=10, repeating the
intitial assertions: “I’m searching, and searching for mice in
FTP works this way: it has a notion of a “working directory” that
stays constant over the course of a session unless you change it. You
might log in to an FTP server,
a certain directory, and
get a file
from that directory. You can
another file from the same directory, without having to issue a second
cd command. Why doesn’t HTTP support
State would make individual HTTP requests simpler, but it would make the HTTP protocol much more complicated. An FTP client is much more complicated than an HTTP client, precisely because the session state must be kept in sync between client and server. This is a complex task even over a reliable network, which the Internet is not.
To eliminate state from a protocol is to eliminate a lot of failure conditions. The server never has to worry about the client timing out, because no interaction lasts longer than a single request. The server never loses track of “where” each client is in the application, because the client sends all necessary information with each request. The client never ends up performing an action in the wrong “working directory” due to the server keeping some state around without telling the client.
Statelessness also brings new features. It’s easier to distribute a stateless application across load-balanced servers. Since no two requests depend on each other, they can be handled by two different servers that never coordinate with each other. Scaling up is as simple as plugging more servers into the load balancer. A stateless application is also easy to cache: a piece of software can decide whether or not to cache the result of an HTTP request just by looking at that one request. There’s no nagging uncertainty that state from a previous request might affect the cacheability of this one.
The client benefits from statelessness as well. A client can
process the “mice” directory up to page 50, bookmark
/search?q=mice&start=500, and come back a
week later without having to grind through dozens of predecessor states.
A URI that works when you’re hours deep into an HTTP session will work
the same way as the first URI sent in a new session.
To make your service addressable you have to put in some work, dissect your application’s data into sets of resources. HTTP is an intrinsically stateless protocol, so when you write web services, you get statelessness by default. You have to do something to break it.
The most common way to break statelessness is to use your framework’s version of HTTP sessions. The first time a user visits your site, he gets a unique string that identifies his session with the site. The string may be kept in a cookie, or the site may propagate a unique string through all the URIs it serves a particular client. Here’s an session cookie being set by a Rails application:
Set-Cookie: _session_id=c1c934bbe6168dcb904d21a7f5644a2d; path=/
This URI propagates the session ID in a PHP application:
The important thing is, that nonsensical hex or decimal number is not the state. It’s a key into a data structure on the server, and the data structure contains the state. There’s nothing unRESTful about stateful URIs: that’s how the server communicates possible next states to the client. (However, there is something unRESTful about cookies, as I discuss in The Trouble with Cookies.” To use a web browser analogy, cookies break a web service client’s back button.)
Think of the query variable
start=10 in a URI, embedded in an HTML page
served by the Google search engine. That’s the server sending a possible
next state to the client.
But those URIs need to contain the state, not
just provide a key to state stored on the server.
start=10 means something on its own, and
RESTfulness requires that the state stay on the client side, and be
transmitted to the server for every request that needs it. The server
can nudge the client toward new states, by sending stateful links for
the client to follow, but it can’t keep any state of its own.
When we talk about “statelessness,” what counts as “state”? What’s
the difference between persistent data, the useful server-side data
that makes us want to use web services in the first place, and this
state we’re trying to keep off the server? The Flickr web service lets
you upload pictures to your account, and those pictures are stored on
the server. It would be crazy to make the client send every one of its
pictures along with every request to
flickr.com, just to keep the server from
having to store any state. That would defeat the whole point of the
service. But what’s the difference between this scenario, and state
about the client’s session, which I claim should be kept off the
The problem is one of terminology. Statelessness implies there’s only one kind of state and that the server should go without it. Actually, there are two kinds of state. From this point on in the book I’m going to distinguish between application state, which ought to live on the client, and resource state, which ought to live on the server.
When you use a search engine, your current query and your current page are bits of application state. This state is different for every client. You might be on page 3 of the search results for “jellyfish,” and I might be on page 1 of the search results for “mice.” The page number and the query are different because we took different paths through the application. Our respective clients store different bits of application state.
A web service only needs to care about your application state when you’re actually making a request. The rest of the time, it doesn’t even know you exist. This means that whenever a client makes a request, it must include all the application states the server will need to process the request. The server might send back a page with links, telling the client about other requests it might want to make in the future, but then it can forget all about the client until the next request. That’s what I mean when I say a web service should be “stateless.” The client should be in charge of managing its own path through the application.
Resource state is the same for every client, and its proper place is on the server. When you upload a picture to Flickr, you create a new resource: the new picture has its own URI and can be the target of future requests. You can fetch, modify, and delete the “picture” resource through HTTP. It’s there for everybody: I can fetch it too. The picture is a bit of resource state, and it stays on the server until a client deletes it.
Client state can show up when you don’t expect it. Lots of web services make you sign up for a unique string they call an API key or application key. You send in this key with every request, and the server uses it to restrict you to a certain number of requests a day. For instance, an API key for Google’s deprecated SOAP search API is good for 1,000 requests a day. That’s application state: it’s different for every client. Once you exceed the limit, the behavior of the service changes dramatically: on request 1,000 you get your data, and on request 1,001 you get an error. Meanwhile, I’m on request 402 and the service still works fine for me.
Of course, clients can’t be trusted to self-report this bit of
application state: the temptation to cheat is too great. So servers
keep this kind of application state on the server, violating
statelessness. The API key is like the Rails
_session_id cookie, a key into a server-side
client session that lasts one day. This is fine as far as it goes, but
there’s a scalability price to be paid. If the service is to be
distributed across multiple machines, every machine in the cluster
needs to know that you’re on request 1,001 and I’m on request 402
(technical term: session replication), so that
every machine knows to deny you access and let me through.
Alternatively, the load balancer needs to make sure that every one of
your requests goes to the same machine in the cluster
(technical term: session affinity).
Statelessness removes this requirement. As a service designer, you
only need to start thinking about data replication when your
resource state needs to be split across multiple