APIs for Microservices — Part 3
In Part 1 of the series we took a look at what really makes microservices different from SOA, and past technologies and methodologies we’ve already tried — and failed to successfully implement. In Part 2 we then took a look at different API types, and best practices for building a RESTful API.
But, as I also shared in Part 1 — any API format when implemented incorrectly will result in your system being glued together, and failing. And ironically, nearly any API — even SOAP — could be successful in decoupling your architecture… and unfortunately, it seems REST is quickly following in its footsteps.
But the real question we need to ask ourselves is why?
It isn’t REST… it isn’t RESTful!!!
What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API. Period. Is there some broken manual somewhere that needs to be fixed?
- Roy Fielding, creator of REST
There are two very simple reasons why we’ve seen REST-like APIs struggle. What has been implemented… and what hasn’t.
What has…
Many of the constraints of REST have been well received, such as allowing for separate evolution of the client and the server, stateless server calls, using a layered system (ie microservices), and many aspects of having a uniform interface.
This has allowed for the creation of relatively easy to use APIs that operate on a very simplistic request-response setup. You call a resource, you choose your method (GET, POST, PUT, PATCH, DELETE), and well, that’s pretty much it!
Of course, the challenge is that these calls are hardcoded into your architecture (remember that glue), add latency (especially when you need numerous API calls to retrieve what you’re looking for), and require computing power (to stitch all the data together). This implementation of Fielding’s dissertation and the problems caused by it have not only creating a myriad of API versions floating around the web, but have been the inspiration for new formats such as GraphQL.
What hasn’t…
However, while half of the constraints have been uniformly accepted, the other half have often times been downright rejected or omitted by the community. This includes sharing cache rules with the client for each data source, utilizing or offering code on demand (the only optional constraint), and providing a uniform interface (which is made up of four subcontraints: identification of resources, manipulation of resources through resources, self-descriptive messages, and hypermedia as the engine of application state).
The irony, is that while many of the new specifications, including GraphQL work to address the problems of current implementations — none (at least that I have seen) provide any solutions to address the items that haven’t. Meaning, that you will find yourself limited to an API that must be static with inflexible models or resources.
For the remainder of this part of our APIs for Microservices Series, we’re not going to try and address all the missing components, but we should take a look at one of the most important, least used, and most misunderstood — HATEOAS.
Hypermedia as the Engine of Application State
One of my favorite questions to ask at tech conferences is how many people have used hypermedia. Usually I’ll get one or two hands raised, and the occasional “I’ve looked at it.” The scary thing is, every single hand should be raised… not because Hypermedia in RESTful APIs is so important (it is), but because hypermedia impacts our lives every day. In fact — you’re probably using it… RIGHT NOW.
After all, broken down the most basic of definitions, hypermedia simply means “more than media” and is considered an extension of hypertext. If the latter sounds familiar, it’s probably because you’re reading this blog post, hosted on the world wide web, written in HTML — the hypertext markup language.
The concept of hypertext is simple — it is text, with links to more text. In other words, you have text, and you can click on a link, and be directed to more text. The same holds true with media — hypermedia is media with links to other media — that’s it.
But despite being incredibly simple, it offers something truly powerful. On the web you can go to any website without any knowledge of how that site is structured, or what you need to do to navigate the site, login, etc. Instead you find an instruction manual that says “click here” to “do this.” You are free to navigate the site with very little context — and in return the site is free to evolve and change without breaking your experience.
This is essentially the purpose of hypermedia in REST — to let the client navigate the server without needing significant context about how the server or API is structured. The client shouldn’t care about business rules, it doesn’t need to know how to handle a user labeled as “admin” vs one labeled as “suspended.” It knows what it can do by the links that are presented. Or as in one of my all-time childhood favorite movies — the API just follows the yellow brick road to find what it’s looking for.
Hypermedia Done Right
This means that the links provided in the API response for each item and general collection need to have meaning. The links should describe the item they represent, where you are, and what can be done with that specific item in the collection.
Just as prev and next links help you understand where you are and where you can navigate within the collection, item specific links need to be able to describe the actions you can take against that specific item.
For example, if you have three users: an admin user, a standard user, and a user that’s been suspended, the actions for each user might be very different:
The correlating hyperlinks returned within the API should likewise be unique for each item — describing the state (or application state):
Admin links: edit, message, suspend
Standard links: edit, message, suspend, delete
Suspended links: unsuspend, delete
The result is a client not having to understand or guess your business logic, allowing it to evolve separately (for example, what happens if you update your rules). The client also no longer has to guess what it “might” be able to do, by making API calls that are destined to fail (ie suspend Joe DaSpammor will fail as he’s already suspended, or trying to delete me would fail as I can’t be deleted — add obscure AI movie reference here).
It also means that links and data can change, and it’s no longer the link that the client is relying on, but the key provided for that action. For example, using the HAL format:
{
"name": "Mike Stowe",
"role": "admin",
"_links": {
"edit": {
"href": "/users/1",
"title": "edit user"
},
"message": {
"href": "/messages/?userId=1",
"title": "message user"
},
"suspend": {
"href": "/users/1/permissions",
"title": "suspend user"
}
}
}
This means that if we need to change the way we handle user IDs, or the way we handle messages, we can update the URL without breaking existing implementations (assuming they rely on “edit.href” and “message.href” instead of the hardcoded link itself):
"edit": {
"href": "/users/2389jd2340-w34d94h3d03-di9h3938hf",
"title": "edit user"
},
"message": {
"href": "/messages/?to=2389jd2340-w34d94h3d03-di9h3938hf&token=d4mo3j9-wdoiejd0-2jlidejh",
"title": "message user"
}
Modern specifications including CPHL and Siren let us do even more, bringing in methods, documentation (HAL can do this, but is limited in its use of Curies, and more):
"edit": {
"href": "/users/2389jd2340-w34d94h3d03-di9h3938hf",
"methods": ["put"],
"title": "edit user"
},
"message": {
"href": "/messages/?to=2389jd2340-w34d94h3d03-di9h3938hf&token=d4mo3j9-wdoiejd0-2jlidejh",
"methods": ["post"],
"title": "message user"
}
Next week
Of course, while hypermedia allows us to remove business logic from the client and create a far more flexible abstraction — there’s a price to pay for it — with increased API calls, latency, and complexity. The very issues solutions like GraphQL focused on fixing. Thankfully, our journey isn’t over — and you aren’t relegated to choosing flexibility over efficiency.
Next week we’ll continue our dive into Hypermedia, it’s role in creating flexible, dynamic APIs that are able to act as the glue between our application and any dependencies, and the specs and formats available today.
Can’t wait? Watch this video to get the Good, the Bad, and the Ugly of Hypermedia!