DEV Community

loading...
Cover image for Hypermedias com Spring HETEOAS

Hypermedias com Spring HETEOAS

daienelima profile image Daiene Lima Updated on ・3 min read

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>
Enter fullscreen mode Exit fullscreen mode
  • 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
Enter fullscreen mode Exit fullscreen mode
  • 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"))));
    }
}
Enter fullscreen mode Exit fullscreen mode

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

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

Alt Text

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

Discussion (1)

Collapse
rmacario profile image
Rafael M Macario

Parabéns pelo artigo.
Tem um typo no título =]

Forem Open with the Forem app