REST

The RESTful HTTP API section said that developers use “RESTful” to mean an HTTP API organized around resources, and that this is looser than what REST originally meant. Now that the API is designed, we can compare it against the original definition.

REST comes from a 2000 doctoral dissertation by Roy Fielding at the University of California, Irvine. Fielding was one of the authors of the HTTP specification, and the dissertation explains why the web’s design works. He described it as an architectural style, a set of constraints on how the parts of a system talk to each other, and he named it Representational State Transfer. There are six constraints. Five of them are required and one is optional.

The constraints

Client-server. The client and the server are separate programs that talk only through requests and responses. Each one can change without the other, as long as the requests and responses stay the same. Everything in this chapter depends on this constraint. The registrar’s office can rewrite its system, and CourseTracker keeps working, because CourseTracker only sees the API.

Stateless. Every request carries everything the server needs to understand it without remembering earlier requests from that client. Our API meets this. The API key is in every request, the page number is in every request, and the term code is in every request. The server does not remember that CourseTracker sent page 1 a moment ago when page 2 arrives. The cost is that the client repeats the same values on every request. The benefit is that a request can go to any server handling the API, without needing to return to the server that handled the client’s previous request. This is what will let the registrar’s office run more than one server behind the API when we get to scaling.

You might wonder whether rate limiting violates this constraint: doesn’t the server remember how many requests a client has sent? It does. Stateless does not mean the server remembers nothing. It means the server does not need an earlier request to understand the current one. The rate-limit counter decides whether to accept a request, not what the request means. When we run several instances of the API, those counts will need to be coordinated across them.

Cacheable. A response says whether it may be cached and for how long. Ours does, with Cache-Control.

Layered system. A client cannot tell whether it is talking to the server or to something in between, such as a cache or a load balancer. Our API meets this. A 304 from a cache and a 304 from the server look the same to CourseTracker.

Uniform interface. This is the constraint that makes an API RESTful in the practical sense, and it has four parts. Resources are identified by URLs. Clients work with resources through representations, which for us is JSON. Messages describe themselves, which for us is the Content-Type header and the status code. And the fourth part is hypermedia: a response carries the URLs of the related resources, so a client can navigate the API by following links, the way a person navigates a website. Our API meets the first three parts and not the fourth. An offering response carries the course number, and a client that wants the course builds /courses/EN.601.226 itself from the documentation. Nothing in the response says where the course is.

Code on demand. The server may send the client code to run, the way a website sends a browser JavaScript. This one is optional, and our API does not use it.

Which constraints the API meets

The API meets five of the six constraints, and three of the four parts of the sixth. That is what “RESTful” means in practice, and it is true of almost every HTTP API that calls itself RESTful. Hypermedia is the part that most APIs leave out, because a client written from the documentation already knows where every resource is, and carrying the URLs in every response makes every response larger for a benefit the client does not use. Fielding wrote in 2008 that an API without hypermedia should not be called REST. Most developers keep the name anyway. They also keep the other five constraints, and those constraints are what make an API designed this way easy to cache and easy for an unknown client to use.