HATEOAS is a way to make your RESTful Web Service endpoint, automatically include links to other Resources of your API, in the response that it sends back to a calling client application.
The client application that consumes your web service endpoint, can then use those links, to consume other RESTful Resources that your Web Service provides.
Let’s say we have a client application that sends HTTP Request to a RESTful web service endpoint to get user details. The web service will respond back with a JSON or XML representation of user details. An example of such a response can be the following JSON representation of user details:
{ "userId": "CfvqLv5fyDCu3sSZiHFJRnsWkZ4ZOk", "firstName": "Sergey", "lastName": "Kargopolov", "email": "[email protected]" }
Having received the above response, the client application has no knowledge about other web service endpoints that it can consume to get additional information about this user. For example, it does not know that this user has two different addresses and that there is a separate web service endpoint to get a list of all user addresses and a separate web service endpoint to get the details of a single address.
With the help of HATEOAS, we can make our Web Service endpoint include links to those other useful web service endpoints the client application can call and get additional details about the user.
Add HATEOAS Dependency to POM.XML
To add HATEOAS support to your Spring Boot application add the following dependency to a pom.xml file of your Spring Boot application.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-hateoas</artifactId> </dependency>
Web Service Endpoint
Now when we have added HATEOAS dependency to our Spring Boot application we can start adding links to a model object that our RESTful Web Service returns. Let’s assume we have the following RESTful Web Service endpoint that returns an object of UserRest class.
@GetMapping(path = "/{id}") public UserRest getUser(@PathVariable String id) { UserRest returnValue = userService.getUserByUserId(id); return returnValue; }
Extending RepresentationModel
The above RESTful Web Service endpoint returns an object of UserRest class. One of the ways to add links to an object of UserRest class is to make it extend the RepresentationModel that comes from org.springframework.hateoas package. If you cannot make UserRest class extend the RepresentationModel, then there is another way to add links to which we will discuss a bit later in this blog post.
import org.springframework.hateoas.RepresentationModel; public class UserRest extends RepresentationModel{ private String userId; private String firstName; private String lastName; private String email; // Setters and Getters need go below. ... }
Adding Links to Response Model Class
Now when our UserRest class extends the RepresentationModel class, we can start adding links to it.
@GetMapping(path = "/{id}") public EntityModel<UserRest> getUser(@PathVariable String id) { // Get User Details UserRest returnValue = userService.getUserByUserId(id); // Create links Link userResourceLink = linkTo(UserController.class).slash(id).withSelfRel(); Link addressesResourceLink = linkTo(UserController.class).slash(id).slash("addresses").withRel("addresses"); // Add links returnValue.add(userResourceLink); returnValue.add(addressesResourceLink); return EntityModel.of(returnValue); }
This will make the above Web Service endpoint return the following JSON Representation of UserRest object.
{ "userId": "enIY0wW4leHgWneVXTopxJH3MAbOV2", "firstName": "Sergey", "lastName": "Kargopolov", "email": "[email protected]", "_links": { "self": { "href": "http://localhost:8080/mobile-app-ws/users/enIY0wW4leHgWneVXTopxJH3MAbOV2" }, "addresses": { "href": "http://localhost:8080/mobile-app-ws/users/enIY0wW4leHgWneVXTopxJH3MAbOV2/addresses" } } }
Using EntityModel to Add Links
Another way of adding links to UserRest class is to use the EntityModel class. In this case, there is no need to make your UserRest class extend the RepresentationModel class.
To add links to an object of UserRest class, you can wrap it into an EntityModel and call the add() method and give it either a single Link or a collection of Links.
EntityModel.of(returnValue).add(userResourceLink).add(addressesResourceLink);
The below code snippet uses the EntityModel to add links. In this case, UserRest class does not extend the RepresentationModel.
@GetMapping(path = "/{id}") public EntityModel<UserRest> getUser(@PathVariable String id) { UserRest returnValue = userService.getUserByUserId(id); Link userResourceLink = linkTo(UserController.class).slash(id).withSelfRel(); Link addressesResourceLink = linkTo(UserController.class).slash(id).slash("addresses").withRel("addresses"); return EntityModel.of(returnValue, userResourceLink, addressesResourceLink); }
Adding Links to a Collection of Resources
If our web service endpoint needs to return a collection of objects, like for example, a list of all addresses, then we need to wrap the resources we are returning into a CollectionModel type.
CollectionModel.of(listOfAddresses);
This will make our web service still return a list of addresses, but because we need to add links to this collection of addresses it will be wrapped into another JSON object.
@GetMapping(path = "/{id}/addresses") public CollectionModel<AddressesRest> getUserAddresses(@PathVariable String id) { List<AddressesRest> listOfAddresses = new ArrayList<>(); // code to populate the listOfAddresses object with addresses return CollectionModel.of(listOfAddresses); }
To add a link to a CollectionModel, you will need to first create a link and then add it to a CollectionModel the following way:
// Create a new link Link userLink = linkTo(methodOn(UserController.class).getUser(id)).withRel("user"); // Add link to a CollectionModel and return result return CollectionModel.of(addressesListRestModel, userLink);
The CollectionModel.of() can accept a single link, a Collection of links, or a variable parameter of Links. So if you need to add more links, you can easily do it.
You can also use the add() method and add the Link object in the following way:
CollectionModel.of(addressesListRestModel).add(userLink);
I hope this tutorial was of some value to you. To learn more about how to build RESTful Web Services with Spring Boot, have a look at my other tutorials in Spring Boot and Spring MVC category on this site.