π What Is HATEOAS?
HATEOAS stands for Hypermedia as the Engine of Application State, a key constraint of RESTful services. It allows a client to interact with a REST API entirely through hypermedia links provided dynamically by the server.
Instead of hardcoding endpoint URIs, the client discovers available actions via embedded links in the API response.
π― Goal
Enhance a Java DTO to include navigable links using Spring HATEOAS. Weβll embed links like:
self
: link to the current resourceall
: link to the collection of similar resources- (Optional)
update
, delete
, or related resource links
π§± Step-by-Step Setup
β
1. Add spring-hateoas
Dependency
In pom.xml
:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
β
2. Create a DTO Extending RepresentationModel
This allows the DTO to hold hypermedia links.
java
import org.springframework.hateoas.RepresentationModel;
public class CollegeDTO extends RepresentationModel<CollegeDTO> {
private Long id;
private String name;
private String website;
// 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 getWebsite() { return website; }
public void setWebsite(String website) { this.website = website; }
}
β
3. Add Links in Controller Using linkTo
and methodOn
java
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("/colleges")
public class CollegeController {
@GetMapping("/{id}")
public CollegeDTO getCollegeById(@PathVariable Long id) {
CollegeDTO dto = new CollegeDTO();
dto.setId(id);
dto.setName("Sample College");
dto.setWebsite("https://samplecollege.com");
// Self link
dto.add(linkTo(methodOn(CollegeController.class).getCollegeById(id)).withSelfRel());
// Link to all colleges
dto.add(linkTo(methodOn(CollegeController.class).getAllColleges()).withRel("all-colleges"));
return dto;
}
@GetMapping
public List<CollegeDTO> getAllColleges() {
return List.of(); // Mocked for simplicity
}
}
π§ͺ Sample JSON Response
json
{
"id": 1,
"name": "Sample College",
"website": "https://samplecollege.com",
"_links": {
"self": {
"href": "http://localhost:8080/colleges/1"
},
"all-colleges": {
"href": "http://localhost:8080/colleges"
}
}
}
π Why Use HATEOAS?
BenefitDescriptionπ DiscoverabilityClients discover available actions via links.π§ Self-navigationNo need to hardcode endpoint paths on client side.π Self-documentingThe API response describes itself.π MaintainabilityChanges to routes are handled server-side, not in clients.
βοΈ Pro Tips
- β
Use
RepresentationModel<T>
for single DTOs. - π§Ύ For collections, use
CollectionModel<T>
or PagedModel<T>
. - π§Ή Keep links dynamic using
WebMvcLinkBuilder
instead of hardcoding. - π Secure link generation (e.g., skip unauthorized actions) if needed.