Spring hateoas
Evolution

Hypermedia as the Engine of Application State
RPC
- Client muss für jede Ressource URI wissen
- keine Contextabhängigkeiten
- statisch
HAL
Hypertext Application Language

{
"id": 4,
"name": "HTL Student",
"number": 100,
"school": {
"id": 3,
"name": "HTL"
},
"_links": {
"self": {
"href": "http://localhost:8080/api/students/4"
},
"students": {
"href": "http://localhost:8080/api/students"
},
"school": {
"href": "http://localhost:8080/api/schools/3"
}
}
}
HATEOAS
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>GET
@GetMapping("/students/{id}")
Student one(@PathVariable Integer id) {
return repository.findById(id)
.orElseThrow(() -> new StudentNotFoundException(id));
}
@GetMapping("/students/{id}")
EntityModel<Student> one(@PathVariable Integer id) {
var student = repository.findById(id)
.orElseThrow(() -> new StudentNotFoundException(id));
return EntityModel.of(student,
linkTo(methodOn(StudentHateosRestController.class).one(id))
.withSelfRel(),
linkTo(methodOn(StudentHateosRestController.class).all())
.withRel("students"));
}
@GetMapping("/students/{id}")
public EntityModel<Student> one(@PathVariable Integer id) {
var student = repository.findById(id)
.orElseThrow(() -> new StudentNotFoundException(id));
return assembler.toModel(student);
}
@Component
public class StudentModelAssembler implements
RepresentationModelAssembler<Student, EntityModel<Student>> {
@Override
public EntityModel<Student> toModel(Student student) {
return EntityModel.of(student,
linkTo(methodOn(StudentHateoasRestController.class)
.one(student.getId())).withSelfRel(),
linkTo(methodOn(StudentHateoasRestController.class)
.all()).withRel("students"));
}
}
POST
@PostMapping("/students")
ResponseEntity<EntityModel<Student>> newStudent(
@Valid @RequestBody Student student) {
Student saved;
saved = trySave(student);
var studentModel = assembler.toModel(saved);
return ResponseEntity
.created(studentModel
.getRequiredLink(IanaLinkRelations.SELF).toUri())
.body(studentModel);
}