REST State Machine Revisited


In the months after the publication of Designing a True REST State Machine and the talk it was based on, there has been quite a bit of discussion and the questions posed should be addressed. While each could be responded to individually, perhaps they might be better served by writing everything up in a blog post. This is that blog post.

The discussion and questions mostly concerned the four misconceptions of REST that were dealt with in the article and talk. These misconceptions are:

  1. REST is just CRUD
  2. Some URI Constructions are more RESTful than Others
  3. REST APIs Should be Versioned
  4. Hypermedia is Optional for REST APIs

Each misconception will be elaborated on below, which will hopefully answer the questions and provide a bit more clarity.

REST and CRUD

Let’s start off by tackling the first REST misconception presented in the talk and article — that RESTful APIs should be designed after the CRUD principle. This was obviously a topic that didn’t get enough time or attention, causing some confusion and misunderstanding.

This topic seems to have struck a chord with Nic Nilov in particular, who writes:

HTTP Method names are not synonymous with CRUD operations for at least one simple historical reason of being established within (at that time) rather distinctly separate realms of computing. Semantically they are not nearly as different as the extent you are trying to stretch to.

Nic Nilov

There’s a difference between HTTP and REST. The point of this topic was that you shouldn’t model your REST API after the CRUD principle. The HTTP methods were just used as an example of why CRUD was not only limiting, but also misguided.

In Fielding’s dissertation (chapter 5.2.1.2), he writes:

REST components perform actions on a resource by using a representation to capture the current or intended state of that resource and transferring that representation between components.

Roy Fielding

The point, which perhaps didn’t come through clear enough, was that in well-designed RESTful APIs, the precise HTTP method used by an operation, is a mostly uninteresting implementation detail. It’s almost, but not quite, as uninteresting as the shape of the URI of a given operation.

In the blog post It is okay to use POST, Fielding writes:

Search my dissertation and you won’t find any mention of CRUD or POST. The only mention of PUT is in regard to HTTP’s lack of write-back caching. The main reason for my lack of specificity is because the methods defined by HTTP are part of the Web’s architecture definition, not the REST architectural style.

Roy Fielding

Designing your API after CRUD limits it to only do Create, Read, Update and Delete. Full stop. CRUD is an artificial limit you or some framework may be imposing on your API that simply doesn’t exist in HTTP or REST. Your API shouldn’t simply be a thin wrapper around your database. As Mike Amundsen tweets:

Remember, when designing your WebAPI, your data model is not your object model is not your resource model is not your message model.

Derek Comartin expands on this principle in a blog post. If you want your API to return something other than a Customer representation after a CreateCustomer request, you shouldn’t let the limits of CRUD inhibit you. Every request to every resource can respond with whatever it wants! Limiting the API to CRUD removes this flexibility, causing many APIs to be burdened by performance problems.

On Using POST

And this segues perfectly to the usage and versatility of POST, of which Nic has the following to say:

SOAP protocol you mentioned uses POST throughout not because of some unprecedented versatility of the method. That is due to the mere fact PUT did not even exists until roughly the same time SOAP spec was made available. PATCH made it into standard ten more years later.

This is somewhat true, but not quite. PATCH was actually defined in the first HTTP/1.1 specification (RFC 2068 section 19.6.1.1), but was removed in the update two years later (the beloved RFC 2616). Either way, even if SOAP was designed today, the only HTTP method that could convey the required functionality and semantics of the protocol is POST.

Going back to Fielding’s blog post on the POST method, he has this to say:

POST serves many useful purposes in HTTP, including the general purpose of “this action isn’t worth standardizing.”

Roy Fielding

Based on this and Fielding’s dissertation, I think it’s easy to see that what matters are state transitions and how you model them. For most state transitions, POST is simply the most suited HTTP method.

Operations should be modeled around abstract concepts like CreateCustomer, CapturePayment and CancelAccount. Whether the API decides to use PUT, POST and DELETE for each of these operations isn’t of much importance, at least not to the client and not to the design of the API. Which HTTP methods the API uses is important only “on the wire” — i.e. in terms of their protocol semantics, whether they are idempotent, how they affect caching, whether they are safe or unsafe, etc.

So for all means, do your homework on how each HTTP method works, but don’t limit your API design to CRUD.

RESTful URIs

On the second misconception — that some URIs are more RESTful than others — Nic Nilov disagrees and argues that the Uniform Interface constraint of REST means exactly that: The shape of the URI and how human friendly it is, matters.

However, the Uniform Interface constraint of REST speaks nothing of the meaning of a URI or how a client must understand its individual parts in order to properly construct it. If you want a client to construct a URI you can use URI Templates (RFC 6570), but hard coding URIs in your documentation and thus also in all of the clients of your API, is a clear violation of the REST constraint that hypermedia must be the engine of application state:

A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API).

Roy Fielding

It’s fine to make the URIs front and center and hard coded in both documentation and clients of your API, but that makes the API noncompliant with REST since it isn’t driven by hypermedia. If that’s a tradeoff worth taking for you, then go for it. Just don’t claim that your API is RESTful.

Versioning

The third misconception — that REST APIs should be versioned — was a topic with so many good questions deserving an in-depth answer that we have published an entire article dedicated to web API versioning. It might provide new ideas on how to tackle changes in your web APIs through a Change Strategy rather than a Versioning Strategy.

Hypermedia As The Engine Of Application State

The fourth and last misconception — that hypermedia is optional — was, not surprisingly, the topic that sparked most discussion and questions.

The Conditionality of Operations

Kevin and Richard Henderson wonders about the conditionality of operations and whether the fact that they aren’t always available will break a client.

First, it’s obvious that the operations a client is built to understand is, in many ways, static. How static a client’s understanding of an API is depends on how rich both the client and API is.

It is possible with JSON-LD and Hydra to use subclassing of operations to make a client understanding a superclass to also perform the action of a subclass.

What HATEOAS means is not that the totality of available operations is highly dynamic, but that each operation is conditional given the current state of a resource.

The conditionality of operations is one of hypermedia’s great strengths. Operations being ephemeral is often the rule, rather than an exception, of hypermedia-driven APIs.

Since available operations are delivered dynamically in each and every response, they can vary by any condition the server chooses. Everything from authorization and the state of 3rd party systems to the weather and phase of the moon can be used as conditions affecting the availability of certain operations. For IoT devices, the latter is not a joke, but reality.

A client can’t know what operations are legal in the current state of the resource without duplicating the server’s state machine. By varying which operations are returned in the given state of the resource, you simplify the state management of the client. It only needs to react to which operations are available at a given moment and act on them.

Without hypermedia, clients have hard coded state management that is serial in nature.

By decoupling the response from the request and by allowing the server to dynamically communicate to the client which operations are available at any given moment, the client can be changed from being serial, hard coded and having complex state management to a simpler, more flexible and reactive UI paradigm.

Hypermedia-driven clients are less coupled, and more flexible and reactive.

Hypermedia’s Role In REST

Nic Nilov makes the point that hypermedia is orthogonal to REST and that you can have hypermedia on any kind of API. He also believes that hypermedia is an optional part of REST, because it adds complexity and therefore needs to be justified.

As the talk and article both point out that hypermedia is more than 70 years old, it’s obvious that it existed long before REST. You can therefore have hypermedia without REST; many examples are given of this in the short history lesson provided.

It’s not the other way around, though. Hypermedia is a clear requirement in REST and not optional. If you create a web API that isn’t hypermedia-driven, it simply isn’t RESTful. End of discussion. Fielding defined what REST is and isn’t — its definition is not up for debate:

“Hypermedia as the engine of application state” is a REST constraint. Not an option. Not an ideal. Hypermedia is a constraint. As in, you either do it or you aren’t doing REST.

Roy Fielding

Nic goes on to say that REST is best suited for long-lived software. This is correct. To be more precise, REST is an architectural style that is mostly beneficial to large (web scale), long-living, distributed systems. That does not make REST unfit for small, short-lived systems, it just means these systems won’t reap all of REST’s benefits.

If you control both the client and the server and you can change both simultaneously — backwards compatibility isn’t an issue and hypermedia would simply introduce overhead. For such APIs, gRPC or something similar might be a better fit.

If you, however, create a public-facing web API with lots of independent integrators writing their own client, the API is meant to live longer than a couple of years and the API consists of many microservices that each serve up a small part of the entirety of the API surface or is distributed in other ways, REST might be a great choice. REST has a higher initial investment — mostly in knowledge — but over time, chances are it’s going to pay off greatly.

Naming and Identifiers

Richard Henderson thinks there’s a chicken and egg problem with HATEOAS and wonders who consumes the links and how it’s possible to know the meaning of each link.

Links and operations are consumed by machines who understand their meaning because they are standardized. These names are usually defined in human readable documentation, such as the one accompanying the API, the IANA Link Relation Registry or similar. Examples of some link relation names standardized by IANA are author, describes and next.

A more distributed and flexible way to create names is through URIs. Since URIs are globally unique identifiers that can be created by anyone, it’s easy to create your own set of “names” that identify the links and operations within your hypermedia vocabulary.

A nice thing about URIs is that they can be URLs, which means that they are dereferenceable. You can paste the URL into a browser and view a web page corresponding to it. If the web page contains documentation about what the “name” or “thing” it identifies means, you have something quite powerful — yet simple — at your disposal.

This system of URLs identifying “things” that are documented on the URL itself is what schema.org is built around. There you can find a plethora of names you can use in your API, such as author, error and identifier.

As the usage of schema.org increases through it being the agreed upon vocabulary for the Structured Data initiatives of Google, Microsoft, Yahoo and Yandex for their search engines, its usage is surely going to increase for APIs as well. With a few standardised vocabularies and a few standardised hypermedia formats supporting them (such as Hydra), clients can stop being unique snowflakes coupled to specific APIs and instead move in the direction of generality and reusability.

The Future of Hypermedia

Nic Nilov finishes off the discussion by saying that HATEOAS is not the first attempt to make resources discoverable and that the previous ones didn’t really work en masse. HATEOAS, like others before it requires commitment to complexity, he argues, something most businesses are not very comfortable with.

This is something it’s hard to disagree with. But there’s hope. Functional programming was seen as nice in theory, but impossible in practice until approximately 10 years ago. Around that time, a flurry of activity happened related to functional programming in almost all popular programming languages. C# 3.0 got lambda expressions, Ruby got an improved lambda syntax and block local variables, Objective C got blocks, C++ got lambdas, etc.

Suddenly, after 50 years of being a theoretical, academic, “useless in practice” concept, functional programming was just as practical and well understood by developers as loops and if statements.

Now functional programming is even proving to be the solution to the failure of Moore’s law. By not sharing state, having immutability and functions as first-class citizens in a programming language, you can parallelize applications in a much safer and simpler way than was possible before with difficult and error prone abstractions such as threads.

The functional systems programming language Rust is one of the greatest testaments to this. With Rust, it is possible to safely and efficiently do parallelization that is simply too hard to express and do reliably and bug-free in most other systems programming languages. Rust is clever in many other ways as well, but its functional properties is the enabler of this power.

There’s reason to believe hypermedia is in the same place as functional programming was 20 years ago. It’s hard to say what’s required for hypermedia to get the same revolution and mind-shift as functional programming did 10 years ago, but through the tedious work of people involved in standardizing hypermedia formats, creating tools, writing guidelines, etc., we might get there one day.