HATEOAS (Hypertext as the Engine of Application State)
It means that the hypertext should be used to find your way through the API. With HATEOAS support in your REST APIs, clients should know just where to start. After getting the first response from the server, they will be able to find their way.Sample REST API without HATEOAS
Below is a sample REST API with Spring MVC
public class Person extends ResourceSupport { private String personId; private String name; private String surname; ... getters and setters } /** * A builder class for building person objects. This class is not necessary. It is just * a better way to create new objects instead of using multiple setters in each line. */ public final class PersonBuilder { private String personId; private String name; private String surname; private PersonBuilder() { } public static PersonBuilder aPerson() { return new PersonBuilder(); } public PersonBuilder withPersonId(String personId) { this.personId = personId; return this; } public PersonBuilder withName(String name) { this.name = name; return this; } public PersonBuilder withSurname(String surname) { this.surname = surname; return this; } public Person build() { Person person = new Person(); person.setPersonId(personId); person.setName(name); person.setSurname(surname); return person; } } @RestController @RequestMapping("/people") public class PersonController { @RequestMapping(value = "/{personId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Person> getPersonById(@PathVariable String personId) { Person person = PersonBuilder.aPerson().withPersonId("1").withName("furkan").withSurname("danismaz").build(); return ResponseEntity.ok(new Resource<>(person, selfLink)); } }
The response of such an endpoint will be:
{ personId: "1", name: "furkan", surname: "danismaz" }
Adding HATEOAS Support with spring-hateoas
- Add the spring-hateoas dependency to your project
org.springframework.hateoas spring-hateoas ...
- Extend ResourceSupport in your model classes
- Change return type of your Controller methods to return Response (or Responses if you are returning a collection).
- Create links and associate them with the returning data using the Resource constructor (or Resources if you are returning a collection)
public class Person extends ResourceSupport { private String personId; private String name; private String surname; ... getters and setters
Note that I just added ResourceSupport as parent class. Nothing has changed other than that.
@RestController @RequestMapping("/people") public class PersonController { @RequestMapping(value = "/{personId}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Resource<Person>> getPersonById(@PathVariable String personId) { Person person = PersonBuilder.aPerson().withPersonId("1").withName("furkan").withSurname("danismaz").build(); Link selfLink = linkTo(methodOn(PersonController.class).getPersonById(personId)).withSelfRel(); return ResponseEntity.ok(new Resource<>(person, selfLink)); } }
In this controller method I've changed:
- The return type of the method from
ResponseEntity<Person>
toResponseEntity<Resource<Person>>
- Created a link
- Created a resource object with a person and a link and returned it as a response
{ personId: "1", name: "furkan", surname: "danismaz", links: [ { rel: "self", href: "http://localhost:8080/people/1", } ], }