HATEOAS Driven REST APIs

HATEOAS (Hypermedia as the Engine of Application State) is a constraint of the REST application architecture which uses hypertext in API response.

hateoas

1. What is HATEOAS

HATEOAS (Hypermedia as the Engine of Application State) is a constraint of the REST application architecture. HATEOAS keeps the REST style architecture unique from most other network application architectures.

The term “hypermedia” refers to any content that contains links to other forms of media such as images, movies, and text.

REST architectural style lets us use the hypermedia links in the API response contents. It allows the client to dynamically navigate to the appropriate resources by traversing the hypermedia links.

Navigating hypermedia links is conceptually the same as browsing through web pages by clicking the relevant hyperlinks to achieve a final goal.

For example, the given below JSON response may be from an API like HTTP GET http://api.domain.com/management/departments/10

{
    "departmentId": 10,
    "departmentName": "Administration",
    "locationId": 1700,
    "managerId": 200,
    "links": [
        {
            "href": "10/employees",
            "rel": "employees",
            "type" : "GET"
        }
    ]
}

In the preceding example, the response returned by the server contains hypermedia links to employee resources 10/employees which can be traversed by the client to read employees belonging to the department.

The advantage of the above approach is that hypermedia links returned from the server drive the application’s state and not the other way around.

JSON does not have any universally accepted format for representing links between two resources. We may choose to send in the response body or decide to send links in HTTP response headers.

HTTP/1.1 200 OK
...
Link: <10/employees>; rel="employees"

Both are good solutions.

2. How to Implement HATEOAS

In the real world, when we visit a website – we hit its homepage. The homepage presents some snapshots and links to other sections of websites. We click on the links and get more information and related links relevant to the context.

Like a human’s interaction with a website, a REST client hits an initial API URI and uses the server-provided links to access the resources it needs and discover available actions dynamically.

The client need not have prior knowledge of the service or the different steps involved in a workflow. Additionally, the clients no longer have to hardcode the URI structures for various resources. HATEOAS allows the server to make URI changes as the API evolves without breaking the clients.

Above API interaction is possible using HATEOAS only.

Each REST framework provides its way of creating the HATEOAS links using framework capabilities. For example, in Spring Boot HATEOAS tutorial, links are part of resource model classes that are transferred as the resource state to the client.

3. HATEOAS References

The following are the two popular formats for specifying JSON REST API hypermedia links:

3.1. RFC 5988 (web linking)

RFC 5988 puts forward a framework for building links that define the relationships between resources on the web. Each link in RFC 5988 contains the following properties:

  • Target URI: Each link should contain a target Internationalized Resource Identifiers (IRIs). This is represented by the href attribute.
  • Link relation type: The link relation type describes how the current context (source) is related to the target resource. This is represented by the rel attribute.
  • Attributes for target IRI: The attributes for a link included hreflang, media, title, and type, and any extension link parameters.

3.2. JSON Hypermedia API Language (HAL)

JSON HAL is a promising proposal that sets the conventions for expressing hypermedia controls, such as links, with JSON or XML. It is in the draft stage at this time.

The two associated MIME types are

media type: application/hal+xml 
media type: application/hal+json

Each link in HAL may contain the following properties:

  • Target URI: It indicates the target resource URI. This is represented by the href attribute.
  • Link relation: The link relation type describes how the current context is related to the target resource. This is represented by the rel attribute.
  • Type: This indicates the expected resource media type. This is represented by the type attribute.

There is no right or wrong in choosing a hypermedia link format for our application. We should pick up a format that meets most of our use case requirements and stick to it.

Comments

Subscribe
Notify of
guest
33 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Tom Außenhofer

I understand this as a valid pattern. But to be honest in real usage this sounds pretty overengineered. I do not see how this simplifies anything. Frontend and Backend will always somehow be coupled to one another via the respective APIs. Why not just use a Client-Side Router and route to the pages you desire based on your Backend API response? This is how every Single Page Application Framework does it with their embedded Routers (e. g. Angular RouterModule). Frontend and Backend are created equal, the frontend shall not be a slave of the backend. 😀

Most of the time you know the whole user journey beforehand, meaning which page to show a user at a specific moment in time. Also conditional routing is possible via Client-Side Routers. I only see it as a reasonable choice, if your user journey is highly dynamic (you do not know what happens next).

Last edited 1 month ago by Tom Außenhofer
Charlie Reitzel

HATEOAS tends towards bloated data in your API and, as others have pointed out, does not relieve the UI from knowing what to expect and how to handle it when it arrives (or not). The examples of the UI using the presence or absence of data sound reasonable but simple links are not sufficient to handle the real world cases, in my experience. Better to have a clean API and, then, extend the API to include permissions info where needed.

A well designed API never forces the UI to know more than it needs to present a good user experience. By itself, HATEOAS does not solve that problem.

Ralph Shillington

I agree 100% and then some. HATEOAS does not scale.

Juan Mendes

The main reason I find HATEOAS useful is because it allows the backend to decide which actions are available so that the UI does not need to know the business logic. For example: a link to withdraw will be hidden if the account is below an amount that depends on many factors. The UI does not have to check the account balance, and check if the user has overdraft protection or keep changing the UI as the requirements change.

Some things I feel are missing and would help me in building UIs:

* The concept of an action being disabled versus being hidden. For example, I can’t start a virtual machine if it’s already powered on so I want to show it disabled. However, if I do not have rights to that VM, I should not see the option at all.
* When actions/links are disabled/missing, that there would be some message so the UI can tell the user if they can do anything about it.
* Schema for the the body

Some of these were mentioned, I just wanted to gather them all into one comment since they are also true in my experience.

like judo

But what if there are a number of options as a ‘next action’ the client can take?
For instance. initial request is GET employees. Now client can POST new address, PUT department, POST update address etc. Where do you specify them?

Gregory Junker

You have a “rel” for each option. For example, the response might contain two rels, “address” and “department”. The HTTP semantics for the API should be well-defined enough, that that is all you need to be able to do the “next thing”.

With the “address” rel, I can GET all of the employee’s addresses, POST a new one, PUT an update for an existing one, etc.

Since the API backend is responsible for access control, it can decide whether even to give me a “department” rel, and if so, what I can do with it (perhaps I can only GET the employee’s department, but if I tried to POST a new one or PUT an update to their linked department, I’d get a 401).

BTW, in your example, I would use PUT for address-update, POST typically is used for creating new resources.

inf3rno

The hyperlink represents an operation you can do on the resource, not the resource itself. The employees relation is a bad example, it should be ListEmployeesByDepartment, or with an object-oriented client you can define a DepartmentResource class and use the listEmployees method and the listEmployees relation if you are in the context of the department resource. You can describe these operation types in the API documentation. They are important because you can decide what data to send and what to expect based on the operation type. If you have security rules and a hyperlink is not allowed for the client, then don’t send it in the response.

Kalyan

I’m still not able to understand how this is all dynamic. We are just sending additional information related to the resource, but how client uses it has to be still coded first in the client. Am i missing something here. The only part i see useful, instead of hard coding the URIs and parameters/specs in the client, we are sending it from the server in the previous call ( this is similar to sending hyper text links in the html content). But the client still needs to know upfront what all actions are possible and the code to build the request and send to the server. It’s not automatic or dynamic.

CAB

Actually the client needs to know how to present each resource in UI, but server provides data to present and actual resources available to the current user.
The dynamic example would be when client building the menu based on links returned for the resource. So server (base on user’s authorization) will return only links accessible for the user and client will build the menu dynamically.
Also client navigation around application will depend on links and embedded resources returned by server. This means that server may change navigation path through the application by moving links between different resources. The only thing need to be built into client — visualization of the resources (which BTW server would know nothing about). This make nice separation of concerns between client and server.

Sammy

Yes, clients needs to know about possible actions, but with hypermedia links they don’t have to know about the business logic. Say you have your typical blog with post resources. Some possible actions might be to like, edit, delete and archive posts. Without links, clients would need to know the business logic about when it is possible to like/edit/delete/archive a certain post resource. With links, the server tells clients what they can do, by providing the corresponding links.
Keeping the business logic on the server side makes it easier to evolve the API without requiring updates of the clients.
HTML is a great example of REST. How often do you update your browser, just because your favourite site changed their html? 😉

William Moore

Nice reply. The first time the HATEOAS made sense to me. I think the point made by others is that the client is not 100% dynamic, but needs to be built with certain expectations about the shape of the data (entities and relations). But using hyperlinks to indicate which paths are valid in a specific instance, that makes sense. Indeed, the business logic could be kept on the server.

wlnirvana

Good point. But unlike the browser (in fact any standardized protocol like HTML, AtomPub, etc), where behaviors are clearly defined when an element (say an ) is present, the expected behavior for the presence/absence of certain hypermedia in customized RESTful APIs is far less consistent.

In the blog example, with HATEOAS of course the client is freed from determining if like/edit/delete is possible for the current application state, but it still has to know in advance what to do if one or more state transitions (e.g. like/edit/delete) are returned in the message. Compared the this burden, the effort saved seems minor.

Anil kumar Sandrapati

we can navigate the user from the backend. suppose user selected for mobile offer. If we want to show data offers as well specific to that user, that we provide as links from the backend. so the client or front end don’t bother about it.

Manjunath D

So here i believe the query is user centric, i would make the URL look like /user/{user_id}/offers?type=[offer_type]

James smyth

What is really missing from this is an example of what the response to either of the following is normally presented..

HTTP GET http://api.domain.com/management/departments
ie. how to communicate that there are 1,2,3 .., 10,. departments,

or the response to
HTTP GET http://api.domain.com/management/departments/10/employees

ie. how to offer the list of employees in dept 10.

CAB

It is easy: each department in first response will be an embedded resource. In case you have too many departments the query may support pagination (links to “first”, “previous”, “next” and “last” pages) or filtering query (in which case I think useful to add field of total count).

Same can be applied to employees in the department. Alternatively you can define employee resource independent of departments and use department as one of filters to group employees. In this case the link for your second request would be a template like http://api.domain.com/management/employees{?department}

Ashish

Hi,

I still don’t understand the purpose of the links as those are just for information and we can always configure swagger integration to provide a proper information about API.
Can someone please let me know one good reason to put these links with the restful response?

Thanks

Juan Mendes

We use it to determine what actions a user has access to. Therefore, the client does not need to know anything about roles or states of entities. All the actions on the screen are enabled/disabled/visible based on the presence of links.

William Moore

In conjunction with the reply by @Sammy, I’m at least beginning to understand the purpose of the HATEOAS. Thanks!

Saiteja

Basically api Connect needs rest api with static back end but ,here including some dynamic rest apis then how can i access those dynamic uri please i need help on this.

Saiteja

hii may i know how we configure this service with api connect
please help me

Rodney Barbati

I’m not sure about the validity of even including a POST in a link – links should be used generally for navigating to a context. A POST would be used to update the server instance of the current context, a PUT would be used to create a new instance of the current context, a DELETE would be used to delete the current context.

But if you had to include a POST in a link, and you wanted to pass parameters with it, it would be as part of the href value. Also, since the URI’s themselves are generated by the server, any parameters you might need should also be generated by the server – it knows the context when it is generating them, so it should be relatively straightforward to include them.

There is a slight disconnect with this spec and the example provided – doing a GET http://api.domain.com/management/departments would not typically return a department as shown (department 10). Rather, it would typically return a list of department ids. Calling GET http://api.domain.com/management/departments/10 would typically be expected to return the object detail for the passed id as shown above.

The examples above actually already show included parameters in the URI – do you notice where it says “href: 10/signatures” – both the 10 and the string signatures are parameters – 10 is the context id, and signatures is the entity we are interested in – this would return a list of signature id’s for department 10.

Bubeeba

In the links, the href value should either be absolute or relative to the current request uri. Given the example above, the request uri is:

//api.domain.com/management/departments/10

Therefore the href value for linking to employees should be either of the following:

/employees
//api.domain.com/management/departments/10/employees

The example gives the link as 10/employees which would result in the href value being incorrect as shown below:

//api.domain.com/management/departments/10/10/employees

ich

Your wording was a littlebit wrong:
– PUT is for UPDATE an entity in a Restful architecture
– POST for INSERT a new entity in a Restful architecture
But POST can be used for other opererations too, if there is no equivalent method is available or implementable (for unknown reason).

Henry

Different teams/organizations implement HTTP verbs in their own fashion and that’s fine, but at least according to the HTTP Specification, the PUT should act as what we commonly refer to as an “UPSERT” – If a resources is found, modify it, else create it:

PUT
If an existing resource is found, then the present request should be viewed as an attempt to UPDATE the existing resource with the resource state representation being provided. (I guess we might be able to debate between whether we should fully destroy the existing resource, and fully replace it with the values being provided – or simply update the existing with those values provided by the user agent in the request. But, that discussion can wait for another day…)
However, if no resource is found, and the resource properties provided allow for the creation of the resource at that URI, then it should be CREATED – AND – a 201 (Created) MUST be returned to the user agent (rule according to SPEC).

POST
Simply said, like PUTS, POSTS can be either UPDATES or CREATES. The main difference with the POST is that the resource is subordinate to the URI and fully defined in the payload, whereas in the PUT, the resource ID is part of the URI itself – meaning you are specifically referring to “resource x” in a PUT.

Example – PUT /questions/10 – Specifically updating or creating question 10.

However, with our POST, some creation flexibility exists allowing you to create your resource and pass back a resource ID value SHOULD YOU CHOOSE TO DO SO – along with a 201 (Created).

Example – POST /questions

Here, the user agent payload allows us to create or update a question, based upon the data provided and the chosen server implementation. We are free to create the question ID of 15000, should that be the next available question ID. However, if an ID is provided, the context of the POST would likely be interpreted as an update. However, the HTTP SPEC allows us to determine those implementation rules/details in the case of a POST.

Finally (at least for this post) there is idempotency… A PUT is idempotent, while a POST is not idempotent. Meaning, you can send the same payload to the same resource and the same effect would occur, the creation of that object will happen only on the first “go-round”, and you can update it 1000 times and it will only update exactly that resource, using the exact same values. So, no additional modifications will occur.

Example Run 1000 times – PUT /questions/10

SHALL at the most create the resource once, and modify question 10 on subsequent processing attempts, using the exact same values. So no change to the resource will occur after the first time this request is processed.

Example Run 1000 times – POST /questions

Using the user agent’s defined payload and depending upon the server’s implementation:
1. This request may create 1000 questions (NOT idempotent).
2. It may take the data provided by the user agent and append it to an ID within the payload (NOT idempotent).
3. Any number of other valid options provided by the server implementation.

CONCLUSION:
Both PUT and POST are used for resource UPDATING as well as resource INSERTION.
A PUT MUST return a 201 (Created) when a new resource is created.
A POST SHOULD return a 201 (Created) when a new resource is created and a Location Header that refers to the new resource.
A PUT’s new resource location IS defined within the URI.
A POST’s new resource location is NOT defined by the URI.
A PUT is idempotent.
A POST is NOT idempotent.

So, this is more that I initially wanted to write, but, I hope it helps more than confuses. For more information, see the HTTP Spec, not another article written with bias, by me, or anyone else – it’s pretty easy to read: https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html.

Hector Jaumandreu

Hi
Thank you for this very useful article.
I’m trying to define an API that guides a Client through a process. In this process after getting a Resource this resource will include a Link indicating the following element that is necessary to create in the process. The plan is add a link like in your example:


{
    "documentID": 10,
    "documentType": "Contract",
    "content": "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
    "links": [
        {
            "href": "10/signatures",
            "rel": "approval",
            "type" : "POST"
        }
    ]
}

But I can’t understand how to indicate the parameters for the POST. Where in the link statement should go?
Thanks for your help.

Sovello

So useful! Have been struggling to understand HATEOAS from an ‘almost-layman-perspective’ and you did it.

Pavan

Instead of xsd schema document why can we just point to swagger file?

Gregory Junker

Certainly you can. XSD is used as an example, but any system that can be consumed by a machine to generate a form suitable for filling by a human will work in this case.