The Three Tenets of API Design (3/3): Respect REST
This is an extract from my book “API on Rails”.
REST is an acronym standing for REpresentational State Transfer and a way of architecturing web services. It was defined in 2000 by Roy Fielding, one of the authors of the HTTP specification and ex-chairman of the Apache Software Foundation, in his dissertation entitled Architectural Styles and the Design of Network-based Software Architectures.
Later on, Fielding described REST as the result of a long discussion of the HTTP specification:
Throughout the HTTP standardization process, I was called on to defend the design choices of the Web. That is an extremely difficult thing to do within a process that accepts proposals from anyone on a topic that was rapidly becoming the center of an entire industry. I had comments from well over 500 developers, many of whom were distinguished engineers with decades of experience, and I had to explain everything from the most abstract notions of Web interaction to the finest details of HTTP syntax. That process honed my model down to a core set of principles, properties, and constraints that are now called REST.
During the last decade, REST has quickly become the de-facto standard for the implementation of public-facing web APIs, even though a few alternatives exist. A comparison of REST with the two most popular web service architectures, SOAP and RPC, can be found in the last paragraph and will help clarify why REST has become so popular.
These are the key concepts of a RESTful web service. We’ll be expanding on what constraints REST imposes on each one of them in the next paragraph.
ResourceA resource is a concept in your application (user, blog post etc.) which can be uniquely identified and operated on. Nouns are preferred over verbs for resource names. When REST is implemented over HTTP, resources are identified through a URI (e.g.
RepresentationA representation is a document which contains the state of a resource. Representations might be created both by the server (when it sends a resource to the client) and the client (e.g. when describing what updates to apply to a resource). For instance, the same user could be served in JSON and XML.
ServerA server stores information about the resources accessible through the web service and allows clients to operate on them. Note that a logical server might consist of several physical servers operating transparently under the same identity. In fact, this is usually the case in large web services, for redundancy and performance. Servers do not expose a UI (User Interface).
ClientA client calls a server to operate a resources. Clients do not store any authoritative information about the resources, but might store context about them and/or how the web service i being used (e.g. authentication information) to improve the UX. Clients also provide a UI which can be graphical, textual or both.
Request/responseRESTful web services operate in request/response cycles. The client sends a request to the server, which handles it and returns a response.
In order to implement REST, a web service has to implement the following architectural constraints.
- Client-Server: Client-server refers to an architecture where the server stores all authoritative information about the resources of the web service. The client does not operate on the resources directly: it merely asks the server to perform operations on the resources.
- Stateless: The server does not store any information about the state of the clients interacting with it. This makes a RESTful service to scale more easily as the number of clients grows. Additionally, it makes implementation and testing much easier.
- Cache: All the responses provided by a server should contain explicit or implicit caching indications (i.e. whether the resource can be cached or not and, if yes, for how long).
- Uniform Interface: All resources on the server should be accessed through the same interface. This minimizes the effort required to learn and use a RESTful service (it arguably makes the implementation easier as well). Over HTTP, this constraint is implemented by using HTTP methods and media types.
- Layered System: A RESTful service is made of one or more layers that can only “see” the next one. These layers can be anything from load balancers to authentication proxies. The client does not know anything about any layers past the most external ones.
- Code-On-Demand: This is an optional constraint of REST: a server can provide code that extends the functionality of and offload certain computations to the client.
If any of the above constraints is not respected, a web service cannot be considered strictly RESTful. The only exception is the Code-On-Demand constraint, which is optional.
The Richardson Maturity Model
RESTfulness is a binary feature: your web service is either RESTful, when it implements all the requirements, or non-RESTful. However, not all non-RESTful services are created alike: some of them are very non-RESTful, some are a little bit non-RESTful, some are five minutes of work away from RESTfulness.
Leonard Richardson devised a scale comprised of four levels of (non-)RESTfulness, where each level builds upon and expands the previous one. It is called the Richardson Maturity Model and Martin Fowlerwrote a blog post that summarizes it pretty effectively, but we’re also going to give our description of it:
- Level 0: Remote procedures over HTTP. This level is the most basic one: at this point, the web service is simply using HTTP as a tunnel to accept requests for a remote procedure and deliver their responses, all through the same endpoint. There is no notion of resource or HTTP method.
- Level 1: Resources. This is the very beginning of RESTfulness: the subjects of the remote calls are encapsulated in logical resources which can be accessed through their own URI.
- Level 2: Methods. As you know from the previous paragraph, HTTP methods are extremely important in a RESTful web service, as clients use them to make certain assumptions about the effect of their requests and the cacheability of the responses. At level 2, we start using the correct HTTP methods for resource URIs.
- Level 3: Hypermedia. This is something that many so-called RESTful APIs get wrong. The Uniform Interface constraint requires that a client only really needs to know about the entry-point of a resource. All subsequent interactions should be made through hypermedia provided by the server along with the resource. We’ll expand on this in the paragraph below (“What is HATEOAS?”).
Again, these four levels are all preconditions of a RESTful web service: they must all be implemented (and more) for a web service to be called RESTful.
What Is HATEOAS?
Here’s another acronym for you: HATEOAS. It stands for Hypermedia As The Engine Of Application State and it’s the concept behind the third level of the Richardson Maturity Model.
The principle is that a client should be able to enter the web service through a fixed entrypoint and perform all subsequent interactions through hypermedia provided by the responses. This distinguishes REST from other architectures where the client constructs its requests from the documentation (either human or machine-readable).
Let’s see an example response from an API implementing HATEOAS (note that HTTP headers are preferred and used in this book, but links can also be included in the body):
GET /posts/1Link: </posts/1>; rel="self",
"title": "My blog post"
As you can see, the response headers contain a
Link header that exposes two links:
- the first one points the client to the requested resource (which should always be included);
- the second one points it to the comments resource related to this post.
Note that the headers do not tell the client anything about what to do with the related resources: they only tell them where they can be found. HATEOAS does not have anything to do with machines magically understanding how to use our API, as it is commonly misunderstood; it simply guarantees that clients can perform a flow of related operations without ever “leaving” the web service.
HATEOAS is what makes REST so resilient to change and so similar to how the web works: when you visit a website, you only enter the homepage’s URL. From that point, all interactions happen by clicking on a link or button (i.e. they are driven by the hypertext). Unfortunately, HATEOAS is also the least implemented of the REST architectural constraints. As a result, a great part of the “RESTful” APIs are not really RESTful (they usually belong to level 2 of the Richardson Maturity Model): if websites worked the same way, you’d have to build all the URLs by hand, referring to the website’s documentation.
The HATEOAS situation is so bad that Roy Fielding wrote a blog post about it. Please, don’t be the guy who makes Roy mad.
REST vs. the Rest
This section briefly compares the REST web service architecture with the most popular alternatives, presenting the advantages and drawbacks of each approach.
It is worth noting that this comparison is not formally correct, since REST is an architectural style, while both SOAP and (XML-)RPC are information exchange protocols. For the sake of simplicity, we will be using the protocol name to also reference an architectural style that uses the protocol.
SOAP (Simple Object Access Protocol) is an information exchange protocol designed in 1998 at Microsoft. It reached the W3C recommendation status in 2003, thus becoming a standard.
SOAP uses XML Information Set (which is not necessarily expressed in XML) to deliver structured information. A SOAP message is made of three (sometimes four) parts:
EnvelopeThe envelope wraps the XML document, identifying it as a SOAP message.HeaderThe header contains application-specific information about the SOAP message.BodyThe body contains the call and the response of the SOAP message.FaultThis section contains any errors occurred while processing the call.
Here’s an example SOAP message (taken from Wikipedia):
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:m="http://www.example.org/stock/Surya">
The SOAP protocol presents many disadvantages when compared with REST:
- because of its verbosity, it requires more bandwidth to send;
- XML is slow to parse (even though XML Information Set can be used with JSON);
- because there is no mandatory vocabulary for expressing operation types, there is no guarantee of operation safety, idempotence or cacheability (these are all things that come for free with HTTP);
- there is tight coupling between the client and the server, which means most server-side changes require the clients to be updated accordingly.
The rigidness of SOAP is, at the same time, an advantage: since both the server and the client must adhere to a pre-defined contract, any violations of the contract are easy to spot automatically.
RPC (Remote Procedure Call) is a kind of request-response protocol that dates back to the beginning of time. At its simplest, a computer sends a request to another computer to perform a specific procedure with specific parameters. The receiver parses the request, performs it and returns a response to the client. There is a bit more to it, but this is explanation will work for our comparison.
RPC can be encoded in many different languages, the most common being XML (JSON is supported too). RPC over XML is called XML-RPC.
Here’s an example XML-RPC request:
And here’s what the corresponding response looks like:
As you can see from the example, the main difference between REST and RPC is that, while REST focuses on information, RPC focuses on function.
RPC has some advantages over REST:
- it is simpler to implement, because designing an RPC service requires less work than designing a RESTful service;
- it is usually preferred in some corporate environments, where the goal is not to structure information in resources but to perform a certain task.
On the other hand, it also has disadvantages: as with RPC, no standard verbs are used, so there is no guarantee of safety, idempotence or cacheability.