emhk.

Spring Boot: Iniciando uma Rest API

08 de Aug, 2023Emanoel Henrick

Primeiro é necessário entender a diferença entre Spring Framework e Spring Boot. Spring é um framework para resoluções de problemas em Java, Kotlin e Groovy, com um sistema que traz injeção de dependências, inversão de controle e diversas outras funcionalidades para facilitar a vida do programador, o Spring Framework tomou conta do mercado e é amplamente utilizado no mundo corporativo.

O Spring Boot por sua vez, veio resolver a dificuldade que era configurar todo o projeto. Trazendo um setup pré-configurado e opinativo, o Spring Boot facilita a definição de configurações usando anotações, também é muito fácil adicionar novas dependências no projeto, bastando apenas adicionar no arquivo de dependências, seja maven ou gradle.

Iniciando o projeto

Existem diversas formas de iniciar um projeto Spring Boot que vão de extensões de IDE, sites como o start.spring.io onde é possivel configurar um projeto do zero e fazer o download até a própria IDE Spring Tool Suite baseada no Eclipse. Após criar o projeto com a ferramenta escolhida e adicionado o Spring Web, já podemos começar a criar os nossos Beans (objetos gerenciados pelo Spring), nesse projeto usaremos Java 17, Spring Boot 3.1.2 e o Maven, também usaremos o Lombok para facilitar a leitura e diminuir o boilerplate.

Spring Web

Spring Web é uma dependência que adiciona todas as dependências do Spring MVC, projeto que permite a criação de aplicações web que usa por padrão o Apache Tomcat. É possível adicionar a dependência durante a criação do projeto ou depois, bastando apenas adicionar a dependëncia no pom.xml:

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

Para adicionar o Lombok:

<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>

Criar controllers é muito fácil, basta anotar uma classe com @Controller e, quando a aplicação iniciar, o Spring vai reconhecer que aquela classe deve ser gerenciada pelo seu container e instanciar automaticamente na inicialização.

Outra anotação importante é o @RequestMapping(X), é essa anotação que vai mapear em X o caminho da URL para o controller. Em aplicações Rest, queremos o Body das requisições e para habilitar o parse para os métodos da classe é preciso usar a anotação @ResponseBody.

Sabendo disso, podemos economizar algumas linhas usando anotações que agrupam outras anotações como é o caso do @RestController que já possui @Controller e @ResponseBody, nossa classe inicial ficaria assim:

@RestController @RequestMapping("/hello") public class HelloController { }

Cada método da classe, pode ser mapeado para um método HTTP por meio das anotações @GetMapping, @PostMapping, @DeleteMapping... Cada annotation pode também receber como parâmetro o caminho da URL como no @RequestMapping.

Existem vários formas de manipular a resposta de cada método, uma delas é devolver um ResponseEntity, a classe cria objetos de resposta com body, status e etc.

@GetMapping public ResponseEntity<String> helloWorld() { return ResponseEntity .status(200) .body("hello world"); }

É possivel simplificar mais usando alguns atalhos da implementação:

@GetMapping public ResponseEntity<String> helloWorld() { return ResponseEntity .ok("hello world"); }

Dessa forma, ao iniciar a aplicação, ficará disponível o endpoint /hello, que ao receber uma requisição GET, irá retornar ao usuário uma String, como definida no generics, "hello world". Existe ainda a anotação @ResponseStatus(X) que devolve por padrão ao usuário, o status X que pode ser definido por meio do enum HttpStatus que possui diversos status predefinidos:

@GetMapping @ResponseStatus(HttpStatus.OK) public String helloWorld() { return "hello World"; }

Pode ser útil quando em utilização com serviços, onde definimos o padrão que um endpoint deve retornar e caso o serviço lançar uma Exception, o Spring captura e devolve ao usuário um erro customizado, vamos ver sobre isso mais a frente.

Recebendo dados no body

Quando enviado um JSON para algum método HTTP, o Spring pode fazer a deserialização e instanciar um objeto contendo as propriedades e valores do JSON recebido por meio da annotation @RequestBody que deve ser usada nos parâmetros do método, vamos criar uma classe simples de usuário para servir de base e vamos usar a annotation @Data do Lombok para diminuir o boilerplate e facilitar a leitura e manipulação da classe:

@Data public class User { private String username; private String password; }

Agora no nosso controller vamos adicionar um endpoint POST de exemplo para receber as informações do usuário e retornar logo em seguida:

@PostMapping @ResponseStatus(HttpStatus.CREATED) public User userRegister(@RequestBody User rawUser) { return rawUser; }

Dessa forma, ao enviarmos no body da requisição um JSON com as mesmas propriedades do objeto User, o Spring vai se encarregar de criar uma nova instância da classe com os valores recebidos:

{ "username": "primeiroUser", "password": "primeiroPassword" }

Caso envie um JSON com alguma propriedade faltando, será criado por padrão um objeto com a respectiva propriedade nula, caso tenha uma propriedade que não existe, será ignorado. É possível adicionar validações para que a API retorne erros customizados caso não seja recebido um JSON com todas as propriedades corretas, mas isso vamos deixar para outro dia!

Recebendo dados nos parâmetros da URL

As vezes precisamos receber dados na URL e o Spring MVC facilita muito a vida do programador nesse sentido. Vimos anteriormente que as annotations que definem os métodos HTTP podem receber também outros parâmetros como o path e para receber variáveis da query basta adicionar o nome da variável entre chaves.

Da mesma forma que o @RequestBody, vamos receber essa variável nos parâmetros do método e precisamos anotar com @PathVariable:

// GET url.com/users/abc123 @GetMapping("/users/{id}") public User findUserById(@PathVariable String id) { // implementação }

Parâmetros de URL, seguem uma idéia parecida com o @PathVariable mas não precisamos especificar os parâmetros na annotation, apenas anotamos o parâmetro no método com @RequestParam:

// GET url.com/users?id=abc123" @GetMapping("/users") public User findUserById(@RequestParam String id) { // implementação }

Ambas as annotations podem ser utilizadas em conjunto e em qualquer método HTTP.