In the previous 28 chapters, we’ve learned a lot about building web APIs following the HTTP principles and the best practices for doing so. Now it’s time to talk about REST, or REpresentational State Transfer.
This chapter is all about REST and its constraints. The first thing we will do, however, is to define what the goals of REST are, and some of the benefits of creating a RESTful API.
After that, we will go back to Alexandria and see why the API we built cannot be called RESTful. We will also attempt to fix it by supporting the missing REST constraints.
Once Alexandria is looking good and hypermedia, we will take a look at some of the prominent hypermedia formats and how they work.
Finally, we will create a simple RESTful API with Grape by using one of the hypermedia formats from the previous chapter.
Before diving into REST, you need to know that REST and RESTful are two overused buzzwords. It is a sad truth, but today, developers use the RESTful term to define HTTP APIs.
RESTful is often put in opposition to SOAP (Simple Object Access Protocol). The problem with this is that SOAP is a protocol, while RESTful consists in adhering to all the REST constraints. So basically, comparing apples with oranges.
What’s even worse is that 99% of those APIs are actually not RESTful since they don’t follow some of the REST constraints. They should only be called HTTP APIs; after all, there’s no shame in not having a RESTful API.
The World Wide Web architecture as we know it today was pushed forward and forged by a group of dedicated people who saw what it could become. It wasn’t, however, as easy to use and leverage as it is today. The creation of standards defining how Web technologies should work and interact with each other allowed the Web to become what it is today.
To create those standards that would make a better Web, it was necessary to identify the flaws of its first versions in the early 90s. That’s exactly what Roy T. Fielding did by analyzing the existing architecture and deriving a set of constraints that made the Web work at that time. By leveraging this set of constraints and adding new ones, REST was created and would become the architectural style of the Web.
With REST, computer scientists were able to define a new direction for the Web that would “reflects the desired properties of a modern Web architecture” [Fielding_dissertation]. While REST was only put down on paper in Fielding’s dissertation in 2000, it existed years before that and was used as a guide to design the 3 fundamental standards of the World Wide Web: HTML, HTTP 1.1 and ECMAScript.
Note that REST is known as an architectural style for distributed hypermedia systems, like the Web. The important word to remember here is hypermedia.
Note that REST is protocol-agnostic, but we will mostly be talking about it in the HTTP context during this module.
Now that we know precisely what REST is, let’s go through each of the six constraints. In his dissertation, Fielding goes through each constraint, starting with a blank architectural schema and ending up with all the constraints represented. For each constraint below, I reused the same kind of schema that are available in the dissertation.
The first constraint is Client-Server. The idea behind this constraint is to separate the user interface concerns from the data storage concerns, and to allow them to evolve independently.
For websites, the clients are web browser that will issue a request to the server and display the returned representation to the user. For web APIs, the client can be pretty much any kind of application that will extract the data from the representation sent by the server and process it.
The second constraint is that communication between the client and the server must be stateless. This means every request from the client must contain all the needed information for the server to understand it without using any context stored on the server. To have stateless interactions between clients and servers, the state must be kept entirely on the client.
The goals of this constraint are visibility, reliability, and scalability, but it also comes with two major drawbacks. First, requests are bigger because they must contain all their contexts and second, the server has no control over the state and cannot enforce a consistent application behavior. Instead, it needs to rely on the different clients implementing the application semantics correctly.
Due to this constraint, HTTP is a stateless protocol. That’s also why the basic authentication mechanisms coming with HTTP (Basic
and Digest
) are stateless as well.
This is, however, one of the least respected constraints because of one HTTP extension: cookies. Most websites use cookies to identify users, keeping a state on the server.
For web APIs, there is also a myth that not using cookies makes an API stateless. That’s not true since most token implementation, like the one we did for Alexandria, that involves a login/logout flow cannot be considered stateless.
If a token is generated for a user on the server, then state is kept on the server and the interactions are not stateless. But keeping state on the server also has advantages and gives more control to the server which is often a requirement. With mobile applications for example, where changes require long and tedious submission and approval processes, having more control on the server makes it easier to debug issues and fix them.
If you’ve ever wondered if your application is stateless, simply ask yourself if any request in your application depends on another one - like a log-in step.
The Cache constraint requires that data sent from a server is explicitly labelled as being cacheable or not. This gives the opportunity to clients to reuse cached responses instead of requesting representations from the server again.
This constraint is embedded in the HTTP protocol, and we have talked about this before. Using specific headers, it is possible to remove the need to make requests entirely or at least reduce the amount of data being transferred.
This constraint is usually respected, thanks to the web frameworks taking care of it for us.
The emphasis on having a uniform interface between components is the main difference between the REST architectural style and other network-based styles. The idea behind this is to allow different components to evolve independently while conserving the same communication interfaces.
In the Web, this mostly happens thanks to HTTP and URIs. HTTP is a shared protocol that transfers data in a standardized way. URIs are interfaces to service implementations.
The uniform interface principle relies on four different architectural constraints:
Let’s go through each one of them.
The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service (e.g. “today’s weather in Los Angeles”), a collection of other resources, a non-virtual object (e.g. a person), and so on.
—Fielding’s dissertation, ch5, p88.
Since resources are the key abstraction in REST, identifying resources becomes a fundamental feature. Within the Web, this is achieved with URIs that identify concepts. Resources are never retrieved by a client, only representations.
To keep the interfaces uniform, resources are manipulated through representations that don’t match how the server internally stores them. This is decoupled to allow implementation and interface to evolve separately.
For example, we might store a concept using different tables in a SQL database, but offer it as one resource with different representations. Those representations could have different formats (JSON
, XML
or HTML
, etc,) or different languages (English, French, etc.), and would be used to manipulate the resource.
Once a client has a representation and its metadata, it should be able to modify or delete a resource, hence manipulating resources on the server.
Messages, or requests for the Web, need to contain enough information to allow any client to understand them. For example, an HTTP request must contain the media type used to format the data in order to use them.
Also known as the hypermedia constraint, it states that clients can only make state transitions (e.g. create a new resource) using hypermedia links provided by the server. This allows resources to be dynamically identified and prevent the client from having to guess and build URIs by itself.
The client should not assume to know how the server works and instead rely on the information provided by the server to perform state transitions. The only required information should be an entry point from which the client can discover what the server has to offer.
While this works great for websites with humans in control and browsers as clients, it’s not doing so great in the world of web APIs. The scenario described above is basically what happens when you access a website. Then, using HTML hypermedia capabilities (<a>
, <form>
), you will navigate to other resources and get their representations.
For web APIs, discovering the API is usually done using an external human-readable documentation. Developers then define code to build resource identifiers (URIs
) which leads to the need of versioning not to break existing hard-coded implementations. The main difference between websites and web APIs is that humans are much smarter than machines at understanding representations.
It is, however, possible to take one step in the right direction by including hypermedia in representations sent from web APIs. This will allow clients to use them instead of relying on database identifiers and manually building the URIs. This reduces the coupling between client and web APIs and should not be ignored.
This constraint defines that it should be possible to create multi-layer systems where each layer doesn’t need to “know” about the layers they are not interacting with.
For the Web, the idea is to be able to include services, caches, and proxies between a client and a server without any problem. Those intermediates should not have to know about the beginning or the end layers; all they should care about are the immediate next layers.
For websites, a good examples of this are Content Delivery Networks that sit “near” the client to provide the requested content as fast as possible. If the content is not available, the request may go through all the layers until the server is reached.
The Code-On-Demand constraint is self-explanatory. It’s also the only optional constraint. The idea is to allow client functionality to be extended by downloading and executing code. This is now very common thanks to the JavaScript language defined by the ECMAScript standard.
Most websites and web applications apply this constraint to provide dynamic features to users. It is, however, optional and pretty rare to find in the wild for web APIs.
This would be an interesting topic to explore, but might prove tedious to implement due to the variety of clients of modern web APIs (mobile applications, other servers, etc.).
Now that we know more about the six constraints defined by REST, we might realize that most web APIs out there are simply not RESTful. The HATEOAS and Stateless constraints are the least respected ones when building web APIs.
Next time you see a web API calling itself “RESTful,” take a close look at their documentation, and perhaps you will realize that it is not a RESTful API after all.
Building non-RESTful APIs is not a crime, and you can just call it what it is: an HTTP API. Especially if you’re building internal tools, simple HTTP APIs are usually more than enough and don’t require new knowledge to be learned by the client implementers.
However, if you’re opening your API to the world, there are some interesting advantages in creating a truly RESTful API, or at least respecting the hypermedia constraint. By using standard hypermedia formats, you make it possible for your clients to use shared libraries to interact with the standard you are using.
The ideal situation here would be that, if Facebook, Google and Twitter had created hypermedia APIs using the same web standards, it would be possible to write one library to interact with them instead of three different ones. I don’t see how it’s possible yet to be honest, but it could be in the future.
The problem will always be that machines need to be able to understand the semantics of an application and its representations if we want web APIs to behave like websites. There is still a big gap to bridge.
Before finishing this chapter, I want to talk quickly about a way to judge to what degree your API is “RESTful.” I personally dislike this idea, since I don’t see the point in defining different levels of “RESTful-ity”. I also don’t believe that building RESTful APIs is possible, or even needed, all the time. Well-designed APIs, sure, but not necessarily adhering to the six REST constraints.
To determine this, Leonard Richardson defined a model known as the Richardson Maturity Model, which has four different levels:
The problem with those levels is that they only focus on the Uniform Interface constraint. You can read more about the Richardson Maturity Model here.
In this chapter, we learned about the origin of REST and what the six constraints that define it are. We went through each one of them systematically to understand exactly what they mean.
In the next chapter, we will review Alexandria and discuss why it is not RESTful and what we could change to make it so.