HATEOAS Driven REST APIs

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

  1. 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.

    Reply
  2. 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.

    Reply
  3. 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?

    Reply
    • 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.

      Reply
    • 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.

      Reply
  4. 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.

    Reply
    • 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.

      Reply
    • 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? 😉

      Reply
      • 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.

        Reply
      • 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.

        Reply
  5. 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.

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

      Reply
    • 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}

      Reply
  6. 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

    Reply
    • Links in REST helps in similar way as they help in HTML. In REST, hateoas links are for “dynamically” discovering the action and resources WITHOUT manual interaction.

      Reply
    • 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.

      Reply
  7. 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.

    Reply
  8. 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.

    Reply
    • 1) POST APIs in HATEOAS links are usually on need basis. For example, if I want to provide a URL where somebody can upload an excel with all new departments information, I will include this API details with HTTP method information – because GET, PUT or any other methods are not valid in this context.

      But in general practice, yes – you are right.
      2) You are right about /departments API. It was a typo and has been corrected. Thanks for noticing and reporting it.

      Reply
      • 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

        Reply
    • 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).

      Reply
      • 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.

        Reply
  9. 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.

    Reply
    • It’s a good question. I will suggest you to add a link to xsd/schema document which will define the structure of model attributes. e.g.

      
      "links": [
          {
              "href": "10/signatures",
              "rel": "approval",
              "type" : "POST",
              "schema" : "/schemas/signature.xsd"
          }
      ]
      

      Now the client can read the XSD document to find out about the model.

      ====================

      Another option can be that design your APIs in such a way that when a resource URL ends with “.xsd” then rather than processing the request, return the model XSD/schema document. In this way, when client want to POST on 10/signatures, it may get the request schema by GET 10/signatures.xsd request or something like this.

      Reply

Leave a Comment