HATEOAS in REST APIs

👉 Implementing Hypermedia Controls in Spring Boot APIs using HATEOAS and HAL Explorer


What is HATEOAS ?

HATEOAS is a constraint of the REST (Representational State Transfer) application architecture. Which mandates that a client interacts with a network application entirely through hypermedia provided dynamically by the application’s responses.

Instead of hardcoding URIs, the server’s responses include links to all possible actions and resources the client can access next. This makes the API self descriptive and allows the server to evolve independently of the client.

Note:
We should leverage HATEOAS (Hypermedia as the Engine of Application State) extensively to build truly RESTful APIs that are self-discoverable and decoupled. It’s a critical principle for robust, scalable microservices.


Table of Contents


Use Cases

The primary purpose of HATEOAS is to make the API discoverable and decoupled. By embedding links, the client doesn’t need prior knowledge of the next possible URI structure.

A typical use case is in a complex workflow, like an e-commerce checkout process, which makes the client-server interaction driven by the application state (Hypermedia as the Engine of Application State).

Where after placing an order, the response includes links for “view details”, “cancel order” or “track shipment”. But if the order is already shipped, the “cancel order” link would be dynamically excluded, reflecting the current state.

Benefits and Drawbacks

AspectDescription
Benefits 📈Decoupling (Client and server evolve independently), Discoverability (Client learns possible actions from the response), Self-Descriptive (API documentation is partially embedded in the response).
Drawbacks 🚧Increased Payload (Links add data to the response), Client Complexity (Client must parse links dynamically, not just data), Initial Learning Curve (More complex than simple data APIs).

Maven Dependency

To enable HATEOAS capabilities in your Spring Boot application, add below dependency in your application’s POM.xml. This provides the necessary APIs for link creation and representation assembly.

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>

Implementation

The Spring HATEOAS APIs simplifies the creation of REST representations.

Some key classes used are EntityModel, a container for a domain object and its links and WebMvcLinkBuilder, a utility to build links pointing to Spring MVC controller methods.

import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.server.mvc.WebMvcLinkBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

// ... other imports for User, UserDaoService, UserNotFoundException

@GetMapping(path = "/users/{id}", produces = {"application/json", "application/xml"})
public EntityModel<User> retrieveUser(@PathVariable Integer id) {
    User user = userDaoService.findById(id);

    if (user == null) {
        throw new UserNotFoundException(String.format("No user exists with id : %s", id));
    }

    // Hateoas: Create link to method (using methodOn to reference a controller method)
    var link = WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(this.getClass()).retrieveAllUsers());

    // EntityModel object supports Model and allows to add links
    final EntityModel<User> entityModel = EntityModel.of(user);
    
    //Hateoas: Add link to Model response object with a specific relation (rel)
    entityModel.add(link.withRel("all-users"));
    
    return entityModel;
}

Explanation

Here’s a brief description of the Spring APIs we have used in above implementation.

  1. WebMvcLinkBuilder.methodOn(this.getClass()).retrieveAllUsers() intelligently inspects the controller method retrieveAllUsers() to construct the correct URI.
  2. linkTo(...) creates the base Link object.
  3. EntityModel.of(user) wraps the domain object (User) to hold the hypermedia links.
  4. entityModel.add(link.withRel("all-users")) adds the generated link to the response with the relation all-users, which describes what the link points to.

Project POC
Check the POC app for reference - SpringBoot HATEOAS POC


Request flow

Below diagram illustrates how the client navigates the application state using links provided in the server’s response, the core concept of HATEOAS.

graph TD
    A[Client sends GET /users/1] -->|Request| B(API Gateway/Controller);
    B -->|Response with User Data| C{User Resource};
    C -->|Embeds Link| D[Link: /users Rel: all-users];
    C -->|Embeds Link| E[Link: /users/1/orders Rel: user-orders];
    D --> F[Client chooses to retrieve all users];
    E --> G[Client chooses to view user's orders];
    F -->|Sends GET /users| B;
    G -->|Sends GET /users/1/orders| B;
    style C fill:#f9f,stroke:#333
    style D fill:#ccf,stroke:#333
    style E fill:#ccf,stroke:#333
    style F fill:#9ff,stroke:#333
    style G fill:#9ff,stroke:#333
    linkStyle 0 stroke:#0f0,stroke-width:2px;
    linkStyle 1 stroke:#0f0,stroke-width:2px;
    linkStyle 2 stroke:#f66,stroke-width:2px;
    linkStyle 3 stroke:#f66,stroke-width:2px;
    linkStyle 4 stroke:#009,stroke-width:2px;
    linkStyle 5 stroke:#009,stroke-width:2px;

Beyond the Basics

We should also be aware of the following advanced aspects of HATEOAS:

ConceptKey DetailImplementation Focus
Media TypesUtilizes Hypermedia-Enabled Media Types like HAL (Hypertext Application Language) to structure responses.HAL defines standard fields: _links (for embedded links) and _embedded (for nested resources), ensuring client-server decoupling. Spring HATEOAS natively supports HAL.
Conditional LinkingLinks should be generated conditionally based on the resource’s current state and the authenticated user’s permissions.Ensures a secure and state-driven experience. An “Approve” link, for instance, is only visible to users with ROLE_MANAGER and if the order status is PENDING.
Link Relations (Rels)Employs standardized and meaningful link relation names (e.g., self, next, prev).Promotes machine readability and client consistency. Custom domain-specific relations can also be defined for unique actions.
Integration with PagingSeamlessly integrates HATEOAS with pagination for collection resources.Links for navigating pages (next, prev, first, last) are automatically included, allowing clients to traverse large datasets without hardcoding URLs.

Best Practices

The current implementation is a great start, but here are a few suggestions to make it more robust and industry-standard:

  1. Use HAL: While EntityModel is fine, consider returning a CollectionModel for lists of resources, and structure your response according to the HAL standard for better client adoption. Spring HATEOAS makes this easy.
  2. Automate Link Generation: For standard CRUD operations, you can use Spring Data REST, which automatically applies HATEOAS principles to repositories, significantly reducing boilerplate code.
  3. Self-Link: Always include a self link in the resource representation to explicitly point back to the resource itself. This is a common HATEOAS convention.