Spring Boot and HATEOAS Designing RESTful APIs
Build discoverable and self-descriptive REST APIs using Spring Boot and HATEOAS
Most developers are familiar with building REST APIs using Spring Boot, but fewer take advantage of HATEOAS — Hypermedia as the Engine of Application State. HATEOAS enables your API to be self-descriptive, allowing clients to navigate available operations dynamically via links provided in the responses.
In this article, we’ll explore how to use Spring HATEOAS to enhance your REST APIs, making them more maintainable, intuitive, and compliant with REST constraints.
What is HATEOAS?
HATEOAS is a key constraint of REST that requires responses to contain hypermedia links to related resources and actions.
Instead of just returning data, your API tells the client what it can do next.
Example (non-HATEOAS):
{
"id": 1,
"name": "Alice"
}
With HATEOAS:
{
"id": 1,
"name": "Alice",
"_links": {
"self": { "href": "/users/1" },
"orders": { "href": "/users/1/orders" }
}
}
This approach increases API usability and makes client interactions more dynamic and resilient.
Adding Spring HATEOAS to Your Project
Add the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
Spring HATEOAS automatically adds support for hypermedia types like HAL (Hypertext Application Language).
Creating a Resource with Links
Spring HATEOAS provides EntityModel
to wrap your response object and add links.
@GetMapping("/users/{id}")
public EntityModel<UserDTO> getUser(@PathVariable Long id) {
UserDTO user = userService.getUserById(id);
return EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(id)).withSelfRel(),
linkTo(methodOn(OrderController.class).getOrdersByUser(id)).withRel("orders"));
}
This wraps the UserDTO
with self and related links, creating a richer, navigable response.
Returning Collections with Links
Use CollectionModel
for lists of resources:
@GetMapping("/users")
public CollectionModel<EntityModel<UserDTO>> allUsers() {
List<EntityModel<UserDTO>> users = userService.getAllUsers().stream()
.map(user -> EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(user.getId())).withSelfRel()))
.collect(Collectors.toList());
return CollectionModel.of(users,
linkTo(methodOn(UserController.class).allUsers()).withSelfRel());
}
This helps clients discover all users and available operations for each.
Supporting HAL and Hypermedia Types
By default, Spring HATEOAS supports HAL. You can specify the desired format via headers:
Accept: application/hal+json
To ensure correct behavior, expose the correct content type using Spring Boot’s auto-configured content negotiation.
Using RepresentationModelAssembler
To avoid duplicating link logic, implement RepresentationModelAssembler
:
@Component
public class UserModelAssembler implements RepresentationModelAssembler<UserDTO, EntityModel<UserDTO>> {
@Override
public EntityModel<UserDTO> toModel(UserDTO user) {
return EntityModel.of(user,
linkTo(methodOn(UserController.class).getUser(user.getId())).withSelfRel(),
linkTo(methodOn(UserController.class).allUsers()).withRel("users"));
}
}
This centralizes the logic of link creation, promoting reuse and consistency.
Advantages of Using HATEOAS
- Discoverability: Clients can explore the API dynamically
- Loose coupling: Fewer hardcoded paths on the client side
- Evolvability: APIs can change without breaking clients
- Improved UX: APIs guide clients on available actions
This leads to better integration across services, especially in distributed systems and microservices.
Best Practices
- Include self links in every resource
- Add relationship links to related resources
- Avoid overloading responses with unnecessary links
- Use
RepresentationModelAssembler
to maintain clean code - Document link structure and relationships clearly
Conclusion
Designing RESTful APIs with Spring Boot and HATEOAS creates a self-navigable interface that simplifies client development and makes your API more expressive and resilient to change.
By leveraging EntityModel
, CollectionModel
, and hypermedia types like HAL, your Spring Boot application can evolve into a truly REST-compliant, user-friendly, and maintainable API.