Hypermedias com Spring HETEOAS
Tags: java, hateoas, springboot, rest
Published: 2020-12-15 02:56:54

#O que é HATEOAS ?
HATEOAS ou (Hypertext as the Engine of Application State) é um modelo que permite que você navegue  entre seus endpoints de forma dinâmica através de links e URLs e sem precisar do conhecimento prévio sobre a API. Nesse caso o cliente descobrirá as URLs  conforme navega entre seus recursos.

Uma boa forma de comparação de HATEOAS é o Hypertext ou Hipertexto que é comum para quem navega na internet diariamente. Quando estamos pesquisando por algo na internet ou lendo alguma notícia e nos deparamos com alguma informação que nos direciona para outro link. 
O mesmo conceito pode ser aplicado a API em que a aplicação consumidora terá um link inicial e a partir dele terá acesso a outros recursos caso necessário. 

>Spring-HATEOAS é uma biblioteca de APIs que podemos usar para criar representações REST que seguem o padrão HATEOAS.

Vamos construir uma aplicação simples com o objetivo de mostrar as vantagens de usar o HATEOAS

* Primeiro adicionamos a dependência do spring-HATEOAS

```
<dependency>			 
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
```

* Criaremos um model

```
@Entity
public class Employee {
	
	private @Id @GeneratedValue Long id;
	private String name;
	private String role;
	
	public Employee() {}
	public Employee(String name, String role) {
		this.name = name;
		this.role = role;
	}
	//gets and sets
```
* Depois vamos implementar a seguinte lógica no nosso controller

```
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.hateoas.CollectionModel;
import org.springframework.hateoas.EntityModel;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.exception.EmployeeNotFoundException;
import com.example.demo.model.Employee;
import com.example.demo.repository.EmployeeRepository;

@RestController
public class EmployeeController {
	
	@Autowired
	private EmployeeRepository repository;


	@GetMapping("/employees")
	public ResponseEntity<CollectionModel<EntityModel<Employee>>> all() {

		List<EntityModel<Employee>> employees = repository.findAll().stream()
				.map(employee -> EntityModel.of(employee,
						linkTo(methodOn(EmployeeController.class).one(employee.getId())).withSelfRel()))
				.collect(Collectors.toList());

		return ResponseEntity.ok(CollectionModel.of(employees));
	}
	
	@GetMapping("/employees/{id}")
	public ResponseEntity<EntityModel<Employee>> one(@PathVariable Long id) {

		Employee employee = repository.findById(id) 
				.orElseThrow(() -> new EmployeeNotFoundException(id));

		return ResponseEntity.of(Optional.of(EntityModel.of(employee, 
				linkTo(methodOn(EmployeeController.class).all()).withRel("employees"))));
	}
}
```
##
O **methodOn()** obtém o mapeamento do método fazendo uma invocação fictícia do método de destino.
O método **linkTo()** inspeciona a classe do controlador e obtém seu mapeamento raiz e finalmente, o **withSelfRel()** qualifica a relação como um link próprio.

Nesse exemplo usamos o CollectionModel ele auxilia na criação de um wrapper para uma coleção de entidades.

####No final temos o seguinte resultado

Se listarmos todos os employees, ele vai retornar no json um link para acessar cada employee individualmente, caso seja necessário.
 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/8ls3p21q28afgbu7dgf1.png)

Se fizemos uma busca por apenas um employee ele nos retorna no json um link para acessar todos os employees

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/kg35ty9lzas3mp2w2ypq.png)

Esse é um exemplo simples onde vemos que o cliente pode ter um único ponto de entrada para a aplicação e outras ações podem ser tomadas com base na resposta. 
Nessa aplicação eu mostrei como Spring HATEOAS promove a descoberta de API em um serviço rest.

link do repositório com o código fonte [projeto-exemplo](https://github.com/daienelima/exemplo-HATEOAS)