Designing a True REST State Machine

There are many misconceptions surrounding what exactly Representational State Transfer (REST) is. The prime of which is the concept of hypermedia, or defined in full context, Hypermedia as the engine of application state (HATEOAS).

Jargon aside, hypermedia is actually a valuable idea that many self-touted “RESTful” web APIs do not adhere to. Hypermedia places heightened operational significance on resources, located at URIs. With a hypermedia API, when a request is sent to a URI, the response lists information on resource state and acceptable future operations, in essence creating a state machine that can be manipulated.

Hypermedia is truly valuable as it can create more powerful APIs that alleviate the need for API versioning. But this is only one of many facets that makes true REST design awesome.

Today, we’re dedicating time to define what exactly REST is and isn’t. Led by RESTafarian Asbjørn Ulsberg, we’ll uncover the history of information design that has led to REST, and debunk some common misinterpretations of REST design.

We’ll also construct a mock state machine and example HTTP behaviors, demonstrating how hypermedia could be used within a REST API to trigger states on an IoT kitchen device. Actually following the REST constraints by building a HATEOAS-compliant API could be very beneficial to advancing the web, so let’s give it the focus it deserves.

Also read the follow up article by Asbjørn Ulsberg: REST State Machine Revisited

The History Behind REST and Hypermedia

Can you guess how old the concept of Hypermedia is? It’s nearly 80 years old. That’s right, in 1941, Argentinian author Jorge Luis Borges wrote The Garden of Forking Paths, a manuscript that contained pages that referenced each other; arguably the first form of hypertext. From Bioshock to Goosebumps, choose your adventure style entertainment and relational data have become commonplace, but in Borges’ time, the book was unprecedented. Some other important strides that have led to REST are:

  • 1963: Ted Nelson coins the terms hypertext and hypermedia.
  • 1968: Douglas Engelbart debuts the On-Line System in the Mother of All Demos, which was the first digital application of hypertext, including mouse pointing, text editing, window environment and more, essentially giving birth to modern word processing.
  • 1987: Apple employee Bill Atkinson creates HyperCard, creating the first successful implementation of hypermedia before the World Wide Web.
  • 1989: Tim Berners-Lee creates the World Wide Web at CERN, implementing the first successful Hypertext Transfer Protocol (HTTP) implementation between a client and server.
  • 2000: Roy Fielding, Co-author of the HTTP and URI specification, writes a doctoral dissertation entitled Architectural Styles and the Design of Network-based Software Architectures. In Chapter 5 he describes Representational State Transfer, or as we commonly call it, REST.

This post was inspired by a talk given by Asbjørn Ulsberg at the 2016 Nordic APIs Platform Summit. Watch it here:

How do we Define REST?

So what is REST? It’s difficult to tackle all the technicalities in a single blog post, so let’s first respond to four misconceptions to understand what REST isn’t.

Common Misconception #1: REST is just CRUD.

CRUD, or Create, Read, Update, and Delete, has become a hallmark acronym amongst data management professionals as it represents the four basic actions for communicating with a database. Though CRUD maps cleanly with SQL actions, as we can see clearly below, it doesn’t map well to HTTP methods:

Operation SQL HTTP
Create INSERT PUT / POST
Read SELECT GET
Update UPDATE PUT / POST / PATCH
Delete DELETE DELETE

Though GET and DELETE coordinate well, POST, PUT, and PATCH aren’t directly synonymous with a single CRUD operation. For example, POST doesn’t necessarily only mean “Create”. It’s actually a very versatile method — so versatile that the entire SOAP protocol is tunneled through the POST method when used with HTTP.

Since HTTP methods don’t map cleanly to CRUD, Ulsberg argues that API providers should consider how they might describe their APIs in a different way:

“Don’t limit yourself to CRUD when you design a REST API. You should read the specification and understand the semantics of each method, and use it properly.”

What it comes down to is that REST is an architectural style, not a protocol. So, calling an HTTP API behaving with CRUD operations “RESTful” is a fallacy.

View our interactive REST vs SOAP Page

Common Misconception #2: Some URI Constructions are more RESTful than Others

Uniform Resource Identifiers (URIs) are vital for defining resources and acting on resources, and are a core concept of REST. However, many developers seem to think they can distinguish a REST API simply based on how the URI is structured. Can you tell which URI is more RESTful than the others?

https://api.nordicapis.com/authors/contributor?author=doerrfeld

https://api.nordicapis.com/blogpost/getPostById?id=47

https://api.nordicapis.com/blogpost/47/edit-form

https://api.nordicapis.com/blogpost/47

https://api.nordicapis.com/128ndoels-8asdf-12d5-39d3

Contrary to popular belief, within the REST guidelines there is no such thing as a RESTful URI construction. To REST, these URIs are simply opaque identifiers — yes, they are global, unique identifiers that can be used for many purposes. However, without knowing more context and the behavior going on under the hood (what the methods look like, what the request looks like, what the response is, etc.) there is no way to tell whether these are RESTful operations or not. What the URI is actually shouldn’t matter, so any of the ones above are as good as the other one.

“Since only machines should read the URIs, and no human, it shouldn’t matter”

The human-readable API design crowd is probably throwing tomatoes at this point. All this isn’t to say that you shouldn’t give attention to making URIs human readable. However, Ulsberg recognizes that you shouldn’t depend on them being represented in any particular way within the client.

For example, say we have very basic documentation for a Nordic APIs Blog Post API, as identified below:

URI Method Description
https://api.nordicapis.com/v1/blogposts POST Creates a new blog post
https://api.nordicapis.com/v1/blogposts/{id} GET Retrieves a blog post
https://api.nordicapis.com/v1/blogposts/{id} PUT Updates a blog post
https://api.nordicapis.com/v1/blogposts/{id} DELETE Deletes blog post
https://api.nordicapis.com/v1/blogposts/{id}/author GET Retrieves blog post author
https://api.nordicapis.com/v1/blogposts/{id}/comments GET Retrieves blog post comments

Just because we’ve listed a URI, Method, and Description for each one of our API calls doesn’t mean that we’ve created a REST API — we’ve just documented our URIs as we would document RPC operations. Stefan Tilkov calls these URI APIs. According to Ulsberg, this puts a huge burden on the clients to understand how to build these URIs, and removes a lot of flexibility from the server.

Misconception #3: REST APIs Should be Versioned

Imagine if we had a database table called ‘Referer’. After much use, we realized that the database name is misspelled, and that we have to change it to ‘Referrer’. Since the clients have already hardcoded the table name in their SQL statements, you can’t update the table, since this means you would have to update all clients — it would be very messy.

Similarly, if we wanted to change one of our /blogposts/ URIs from above, we would be in the same tricky situation — we would have to update all clients. This leads to creating a v2, updating documentation, and asking clients to kindly update everything. In short, having hardcoded versioning in the URI is a painful process.

Upon whether or not to version web APIs, Roy Fielding’s keynote presentation for the 2013 Evolve Conference simply states:

“DON’T”

Misconception #4: Hypermedia is Optional for REST APIs

Nope. As Roy Fielding himself stated in a 2014 interview with Mike Amudsen:

“ ‘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.”

So what is hypermedia exactly? Well, REST consists of 6 major constraints. Out of these, HATEOAS is arguably the most important and unique to the REST stipulation, but also the least understood.

  1. Client-Server
  2. Stateless
  3. Cacheable
  4. Layered
  5. Code on demand (optional)
  6. Uniform Interface
    • Identification of resources
    • Manipulation of resources
    • Self-descriptive messages
    • Hypermedia as the engine of application state (HATEOAS)

To understand HATEOAS, Ulsberg recommends we apply the same thinking proposed by Don Norman in The Design of Everyday Things. As a cup wants to be held and lifted, or a button wants to be pushed, hypermedia wants to tell you what to do with the resource. Hypermedia is links and metadata for operations that help developers or machines perform additional actions. As Ulsberg says:

“If you look at hypermedia as a recipe of how the next request is supposed to look like, you will grasp what hypermedia is all about”

Example State Machine: IoT Toaster

So let’s delve into what hypermedia actually looks like. To describe hypermedia as the engine of application state, let’s take a simple example of a possible state machine — a connected toaster that can be manipulated through the internet.

A state machine is a concept within computer programming that is used to describe a machine that has a set of states, usually with input and output events. In this case, our toaster begins in an off state. After turned on, it enters the heating state. Then it reaches its upper temperature limit and enters an idle state, which reduces the temperature. By being idle it cools, and goes back into a heat state. It continues this loop, maintaining a constant temperature until the bread is toasted, after which it shuts down.
How could you manipulate such a toaster through REST and hypermedia? Well, as Roy Fielding described, hypermedia is the engine of application state. Each page on the web represents a single state of a single resource, which can be obtained using a GET call. It is implicit that you are able to retrieve anything with an ID at a URI. So, let’s first call our toaster to see what we get back:

GET /toaster HTTP/1.1

The response looks something like:

HTTP/1.1 200 OK

{
	"Id": "/toaster",
	"state": "off",
	"operations": [{
		"rel": "on",
		"method": "PUT",
		"href": "/toaster",
		"Expects": { "state": "on"}
}]
}

As you can see, we have an id at the top to denote what resource we are communicating with. The current state is displayed, as well as a list of possible operations that we may enact on the machine.

So let’s try to actually alter the state of the toaster. We’ll send a PUT HTTP request for this:

PUT /toaster HTTP/1.1

{
    "state": "on"
}

Our response will look something like:

HTTP/1.1 200 OK

{
	"Id": "/toaster",
	"state": "on",
	"strength": 0,
	"operations": [ {
		"rel": "on",
		"method": "PUT",
		"href": "/toaster",
		"expects": { "state": "off" }
	}, {
	"rel": "strength",
	"method": "PUT",
	"href": /fcesj48fl29304d827434j
	"expects": {
		"strength": [1,2,3,4,5,6]
		}
}]
}

We have now turned on the toaster! However, as we can see above, the strength is still set to zero, so it isn’t heating yet. Let’s see what happens when we make a call to affect the strength operation.

PUT /toaster HTTP/1.1

{
    "strength": 3
}

So when we execute this strength operation, we see that the state has changed, and the toaster is now heating:

HTTP/1.1 200 OK


{
	"Id": "/toaster",
	"state": "heating",
	"strength": 3,
	"operations": [ {
		"rel": "on",
		"method": "PUT",
		"href": "/toaster",
		"expects": { "state": "off" }
	}, {
	"rel": "strength",
	"method": "PUT",
	"href": /fcesj48fl29304d827434j
	"expects": {
		"strength": [1,2,3,4,5,6]
		}
}]
}

We still have other options, as laid out in the hypermedia above. We can chose to turn it off, or adjust the strength again. But instead, let’s send another GET to the toaster ID.

HTTP/1.1 200 OK


{
	"Id": "/toaster",
	"state": "idle",
	"strength": 3,
	"operations": [ {
		"rel": "on",
		"method": "PUT",
		"href": "/toaster",
		"expects": { "state": "off" }
	}, {
	"rel": "strength",
	"method": "PUT",
	"href": /fcesj48fl29304d827434j
	"expects": {
		"strength": [1,2,3,4,5,6]
		}
}]
}

Since our last request, the toaster has entered an idle state. You can see that we can still opt to turn it off, or adjust the heating temperature with the strength operation.

Wait a few minutes, and another request to the state machine will likely result in a state of “shutting down” which may include no operations, or “off” — the initial resting state with the list of possible operations still in the response.

Conclusion

The web functions as a web of interconnecting ideas, linked with hypertext. Ulsberg believes that web APIs should mimic this, and that an important facet in doing so is implementing hypermedia within our APIs. For those newcomers to REST, Building a HATEOAS-compliant API is a huge improvement over RPC-style APIs:

If you use hypermedia, you can add relations and links, and operations to the resources without breaking existing clients, and at the same time, giving new functionality to new clients.

This also means rethinking the traditional stance on versioning. On versioning, Ulsberg’s thoughts echo Fielding: don’t. When did you last see a versioning number on a website? As HTML doesn’t need a version number, JSON shouldn’t either.

By putting more emphasis on the resources as state machines, we can communicate the current state to consumers through which operations we make available. This reduces coupling and in business domains where the application state consists of many complex and interdependent factors, and will make the client much simpler. This is the power of REST. This is the power of hypermedia.