HATEOAS stands for Hypermedia As The Engine Of Application State. It is a technique that is often used in conjunction with REST APIs.
The basic idea of HATEOAS is that when your API returns a resource, the representation should include links that allow the consumer of the API to discover resources related to the current one. It’s similar to the way websites work. When people open a web page, it contains links to further pages, and they can use these links to navigate without any other information.
Let’s see a simple example where we are getting back the details of a user:
{ "id": 19, "name": "JohnDoe", "email": "john.doe@gmail.com", "links": [{ "href": "/users/19/comments", "rel": "comments", "method": "GET" }, { "href": "/users/19", "rel": "delete", "method": "DELETE" } ] }
As you can see we have a links
array, which contains two links. One for getting the comments made by the user, and one for deleting the user. Because these links are provided, the consumer of the API do not need to know them. It only has to know where to find them. And of course, it needs to know the possible actions about a resource. In this case, it needs to know in advance that a user has comments and that it can be deleted, otherwise, the rel
attribute wouldn’t make too much sense to the client.
This is not the only syntax that can be used for providing the links, but it’s a fairly standard one.
Here is a more real life example from the PayPal API:
{ "links": [{ "href": "https://api.paypal.com/v1/payments/sale/36C38912MN9658832", "rel": "self", "method": "GET" }, { "href": "https://api.paypal.com/v1/payments/sale/36C38912MN9658832/refund", "rel": "refund", "method": "POST" }, { "href": "https://api.paypal.com/v1/payments/payment/PAY-5YK922393D847794YKER7MUI", "rel": "parent_payment", "method": "GET" }] }
Why use HATEOAS?
The biggest advantage of this approach is that consumers of the API do not have to hardcode the API URLs into their code. They just have to know where to find them. This allows the API developers to freely change the URL structure as it won’t break the clients.
Limitations
In an optimal case, HATEOAS would allow a consumer to start from a “root” resource and just by going through the links, discover the URL for any endpoint and use it. To an extent, it can work. For example, if we are trying to get the likes received by a user for a specific post, a client could automatically
- GET the user
- GET the posts of the user
- GET the specific post of the user
- and finally, GET the likes for that specific post
All this based on the links returned in the response for each request.
This approach would not work if we need some extra information to be able to submit the request. For instance, if I want to create a post for a user, I need to know what fields do I have to submit. I can get the target URL from the response, but getting all the information about the fields would be pretty tricky. Even if I would get back the list of fields in the response, I would need to have a logic in place that can determine the correct value for each field.
Summary
The HATEOAS technique can be very useful if we are not trying to overuse it. It’s great when we would like to automatically discover content/endpoints to decouple the clients from the API. But we should not try to construct an API that is fully describing itself using this technique because in most cases, this would not be possible in a dynamic way.