Why HATEOAS is useless and what that means for REST
In this article I want to publish my thoughts on a very opinionated matter: The central constraint of RESTful APIs, HATEOAS. Have you ever wondered why API versioning is so hard and much discussed in REST? This is the reason. For anybody unfamiliar with it, I will introduce you to REST and it’s principles first.
In general, REST is an architectural style that Roy Fielding described in his doctoral dissertation. It is mainly defined by a couple of architectural constraints. These are:
- Client-Server Architecture
The simple goal of this constraint is the separation of concerns between client and server.
- Stateless Communication
This constraint improves scalability, visibility and reliability by simplifying the server implementation.
- Explicit Caching
“An interesting observation is that the most efficient network request is one that doesn’t use the network.” — Fielding in his dissertation.
I think it is pretty clear why caching is desirable.
- Layered System
The layered system constraint aims to reduce complexity by encapsulating legacy services and introducing intermediary systems. Even though this is adding a bit of overhead, it can be offset by using caches in the REST architectural style.
- Uniform Interface
This is really the main constraint distinguishing REST from other styles. A uniform interface means that client and server can evolve independently and components are decoupled. It is not this simple in reality though, as I will explain later.
- An optional constraint for Code-on-Demand can be used, but as it is optional I will not discuss it further.
In theory, all these constraints sound solid and are very useful, but I want to discuss the Uniform Interface a bit more, as it is the most important constraint in REST.
To achieve the Uniform Interface, REST uses another set of constraints, Fielding calls these “Interface Constraints”.
- Identification of resources
- Manipulation of resources through representations
- Self-descriptive messages
- Hypermedia as the engine of application state (HATEOAS)
Using resources and representations is easily achieved, and with self-descriptive formats like JSON and XML, the third constraint is also very clear. But what exactly does HATEOAS mean?
“Hypermedia as the engine of application state” is not explained in the dissertation, but on his blog Fielding specified it further:
When I say hypertext, I mean the simultaneous presentation of information and controls such that the information becomes the affordance through which the user (or automaton) obtains choices and selects actions.
This means that HATEOAS should guide a user through the interface by offering control alongside the data. A client would use these to navigate through the interface dynamically.
In an ideal REST interface, the client should only know the root URI and can browse and use the entire interface by following links if it knows all the media-types that the server uses for his representations.
This is a very powerful mechanism, allowing client and server to be developed independently and it creates great possibilities like dynamically directing to another server without any changes in the client. If you have trouble visualizing it, it should work like a browser: You can click on any link or website and navigate through it by following subsequent links, it does not matter what server you are on. This works because the browser knows the media type that is used (HTML). There are countless articles on the internet with great explanations of the concept.
The problems with HATEOAS
As I wrote in the title, HATEOAS for APIS just does not work and most of the time it is not even used. There are two main reasons for this:
- There are very few good tools to create a REST API using this style
- There are no clients widely used to consume these types of APIs
Of course projects like Spring HATEOAS exist, and there are some implementations for REST-crawlers, but if you have a public facing API, you can be 100% certain that your clients won’t use them.
This renders the whole concept of HATEOAS useless. You use it to gain loose coupling and evolvability by creating a generic interface. But if your clients don’t use your API in the correct way, HATEOAS becomes completely useless.
So what does that mean for REST?
- You will have to create an API specification
Because your clients will not dynamically discover your API and are not RESTful you will have to provide another way for them to understand your API. In my opinion there is a reason why there is no official standard tool for creating a specification for REST interfaces: Most of the tools are not truly RESTful.
- You will have to version your API.
The evolvability we were supposed to gain from HATEOAS can not be delivered. This is problematic because REST was not meant to be versioned another way, and lots of discussion is going on if you should use a /v1/ or how this can be achieved:
“The reason to make a real REST API is to get evolvability … a “v1” is a middle finger to your API customers, indicating RPC/HTTP (not REST)” — Fielding on twitter
In the end, this means that REST is not that different from RPC. It uses resources, representations and self-descriptive messages and is subject to some great constraints. However, the main benefit of HATEOAS does not work in practice. This means that there are some pain points in REST concerning versioning and evolving your API.
REST is still a great way to create APIs, but it is not the holy grail, it has some problems, and it is closer to RPC than some REST lovers like to admit.
It is very refreshing to see some new tools for creating APIs with a more flexible mindset or a different set of goals like GraphQL or GRPC.
Most of all, everybody should realize that REST is not the only choice anymore, and it is not always the best choice.