Introduction

In this tutorial, we are going to implement HATEOS in our Spring JPA project. In our last series, we discussed the Spring JPA and how it can be implemented. The aim of this tutorial is to introduce dynamic URL resource generation.

HATEOS a brief note

HATEOAS (Hypermedia as the Engine of Application State) is a principle that allows REST APIs to evolve over time without breaking the client. Add a layer of discoverability to your RESTful APIs by allowing clients to dynamically navigate your APIs via links included in response payloads. Hypermedia is an essential area of REST that allows one to set up services that continue to develop independently of each other, with significant separation between client and server. The representation returned for a REST resource contains not only data but also links to related resources. The representation design is therefore crucial to the service’s overall design of the service.

Setup Requirements

  1. Maven 
  2. Spring Boot 2.7.8
  3. JDK 1.8 and above
  4. Spring HATEOS
  5. Spring Data JPA

Adding HATEOS to pom.xml

To enable our application the ability to use HATEOS, we have to add the spring boot dependency support for HATEOS in our pom.xml file. 

Our Model

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.8</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.valerio.nu</groupId>
	<artifactId>spring-data-jpa</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-data-jpa</name>
	<description>Develop a simple restful service with spring data jpa</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>2.1.214</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>com.mysql</groupId>
			<artifactId>mysql-connector-j</artifactId>
			<scope>runtime</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-hateoas</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-hateoas</artifactId>
			<version>2.7.8</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.hateoas</groupId>
			<artifactId>spring-hateoas</artifactId>
			<version>1.4.0</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

In this tutorial, we have created a User model with properties such as firstname, lastname and username. 

The Service and interface implementation is where our business logic was defined.

Our REST Controller shows the integration of HATEOS ability. As shown in the code below, EntityModel is used to bind the User model while the linkTo creates a reference to the URL resource desired.

 @GetMapping(value = "/users/{id}")
    public EntityModel<User> Get(@PathVariable int id) {


        User result = userService.Get(id);
                if(result == null){
                    throw new ObjectNotFoundException("no user exist with such id: " ,  String.valueOf(id));
                }

            return EntityModel.of(result, //
                    WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(this.getClass()).Get(id)).withSelfRel(),
                    WebMvcLinkBuilder.linkTo(WebMvcLinkBuilder.methodOn(this.getClass()).Get()).withRel("all-users"));


    }

Our goal here in the REST controller is the ability to Implement a method of how to create a link pointing to the controller method and how to add it to the restful representation model. Both linkTo(…) and methodOn(…) are static methods of WebMvcLinkBuilder were used to achieve the reference. The returned LinkBuilder consults the Controller method’s mapping annotations to construct the exact URI that the method maps to. Calling withSelfRel() creates a Link instance to add to the User’s model. 

The result is a restful representation that returns the URL of other requests defined.

HATEOS result showing links

Conclusion

Implementing HATEOS in spring boot Restful calls is important as it enables dynamic URL representation. The source code for this project is available on our GitHub page.

Leave a Reply