Spring Boot – Building REST APIs with HATEOAS
Last Updated :
22 Aug, 2024
In this article, we will explore how to build RESTful APIs using the Spring Boot with HATEOAS (Hypermedia as the Engine of Application State). HATEOAS is the key component of the REST application architecture, where each resource not only provides the data but also includes links to other actions that can be performed on the resource. This approach allows the clients to navigate through the application using these links, making the API more dynamic and discoverable.
HATEOAS in Spring Boot
HATEOAS is the concept within REST that enables the client to interact with the RESTful service entirely through hyperlinks provided dynamically by the service itself. It means the client does not need to hardcode the URIs of the resource but can discover them at runtime.
In Spring Boot, HATEOAS can be implemented using the spring-boot-starter-hateoas dependency which allows the easy creation of hypermedia links and resources. With HATEOAS each resource representation returned by the server can contain the links to related resources or actions that the client can follow.
Implementation to Build REST APIs with HATEOAS in Spring Boot
Step 1: Create a new Spring Boot Project.
Create a new Spring Boot project using IntelliJ Idea. Choose the below options:
- Name: Spring-HATEOAS-Demo
- Language: Java
- Type: Maven
- Packaging: Jar
Click on the Next button.
Step 2: Add the Dependencies
Add the following dependencies into the Spring Boot project. click on the create button to create the project.
Step 3: Project Structure
Once created the project, the file structure looks like:
Step 4: Configure Application Properties
Open the application.properties file and add the following configuration:
spring.application.name=Spring-HATEOAS-Demo
spring.datasource.url=jdbc:mysql://localhost:3306/employee_db
spring.datasource.username=root
spring.datasource.password=mypassword
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
Step 5: Create the Employee Entity
Create the Employee Entity class represents the database table structure of the Spring Boot project.
Java
package com.gfg.springhateoasdemo;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String role;
// Constructors
public Employee() {}
public Employee(String name, String role) {
this.name = name;
this.role = role;
}
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
Step 6: Create the EmployeeRepository Interface
Now create the EmployeeRepository class can be extends JpaRepository to provide the CRUD operations.
Java
package com.gfg.springhateoasdemo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Step 7: Create the EmployeeService Class
Now create the EmployeeService class contains the business logic for the CRUD operations of the project.
Java
package com.gfg.springhateoasdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
public Employee createEmployee(Employee employee) {
return employeeRepository.save(employee);
}
public Employee getEmployeeById(Long id) {
return employeeRepository.findById(id).orElse(null);
}
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
public Employee updateEmployee(Long id, Employee employeeDetails) {
Employee employee = getEmployeeById(id);
if (employee != null) {
employee.setName(employeeDetails.getName());
employee.setRole(employeeDetails.getRole());
return employeeRepository.save(employee);
}
return null;
}
public void deleteEmployee(Long id) {
employeeRepository.deleteById(id);
}
}
Step 8: Create the EmployeeController Class
Create the EmployeeController class handles the HTTP requests and adds the HATEOAS links of the application endpoints.
Java
package com.gfg.springhateoasdemo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
@RestController
@RequestMapping("/employees")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping
public EntityModel<Employee> createEmployee(@RequestBody Employee employee) {
Employee createdEmployee = employeeService.createEmployee(employee);
return toHateoasEntityModel(createdEmployee);
}
@GetMapping("/{id}")
public EntityModel<Employee> getEmployee(@PathVariable Long id) {
Employee employee = employeeService.getEmployeeById(id);
return toHateoasEntityModel(employee);
}
@GetMapping
public List<Employee> getAllEmployees() {
return employeeService.getAllEmployees();
}
@PutMapping("/{id}")
public EntityModel<Employee> updateEmployee(@PathVariable Long id, @RequestBody Employee employeeDetails) {
Employee updatedEmployee = employeeService.updateEmployee(id, employeeDetails);
return toHateoasEntityModel(updatedEmployee);
}
@DeleteMapping("/{id}")
public void deleteEmployee(@PathVariable Long id) {
employeeService.deleteEmployee(id);
}
private EntityModel<Employee> toHateoasEntityModel(Employee employee) {
Link selfLink = linkTo(methodOn(EmployeeController.class).getEmployee(employee.getId())).withSelfRel();
Link allEmployeesLink = linkTo(methodOn(EmployeeController.class).getAllEmployees()).withRel("all-employees");
return EntityModel.of(employee, selfLink, allEmployeesLink);
}
}
Step 9: Main Class
No changes are required in the main class.
Java
package com.gfg.springhateoasdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HateoasApplication {
public static void main(String[] args) {
SpringApplication.run(HateoasApplication.class, args);
}
}
pom.xml file
XML
<?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>3.2.8</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.gfg</groupId>
<artifactId>Spring-HATEOAS-Demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Spring-HATEOAS-Demo</name>
<description>Spring-HATEOAS-Demo</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
Step 10: Run the Application
Once completed the project, it will start and run at port 8080.
Step 11: Testing the Endpoints
1. Create Employee
POST http://localhost:8080/employees
2. Get All Employees
GET http://localhost:8080/employees
3. Get Employee by ID
GET http://localhost:8080/employees/1
4. Update Employee
PUT http://localhost:8080/employees/1
5. Delete Employee
DELETE http://localhost:8080/employees/1
By following these steps, we can test each of the CRUD operations for the Spring Boot application with HATEOAS and MySQL. Each request should be conform to the structure and links defined in the example project.
Similar Reads
How to Build a RESTful API with Spring Boot and Spring MVC? RESTful APIs have become the standard for building scalable and maintainable web services in web development. REST (Representational State Transfer) enables a stateless, client-server architecture where resources are accessed via standard HTTP methods. This article demonstrates how to create a RESTf
7 min read
A Guide to RestClient in Spring Boot In Spring Boot applications, external services often need to be communicated via REST APIs. Traditionally, RestTemplate was used for this purpose, but it is now considered a legacy approach. Starting from Spring Framework 6.1 and Spring Boot 3.2, RestClient has been introduced as a modern alternativ
9 min read
Securing REST APIs with Spring Security In Spring Boot applications, securing the REST APIs is a critical aspect of developing secure and robust applications. REST APIs are commonly used to expose functionalities to external systems, mobile applications, and web applications. Without proper security measures, these APIs can become targets
8 min read
Best Practices while Making Rest APIs in Spring Boot Application API, or Application Programming Interface, is a communication gateway between frontend and backend code. A robust API is crucial for ensuring uninterrupted functionality. In this article, we will discuss how to achieve robustness in our REST API within the Spring Boot application. Rules : Use JSON a
7 min read
Spring Boot - REST API Documentation using OpenAPI For any application, API documentation is essential for both users and developers. How to use an API, what will be the request body, and what will the API's response be? API documentation is the answer to all of these questions, springdoc-openapi is a Java library that automates the generation of th
4 min read