⁠Como validar o body de uma requisição com Spring Boot

Aprenda a validar dados no Spring Boot! Veja como fazer a validação de forma eficiente, centralizando regras e garantindo mais segurança para sua aplicação. Evite dados inválidos e torne seu backend mais confiável.

⁠Como validar o body de uma requisição com Spring Boot
Como validar o body de uma requisição com Java | Spring Boot

Quando estamos desenvolvendo APIs com o Spring Boot, uma das primeiras coisas que precisamos fazer é garantir que os dados recebidos nas requisições sejam válidos antes de processá-los.

1. Pré-requisitos para esse artigo

Nesse artigo estou considerando que você já tenha um projeto inicial em Spring Boot e conhecimento básico de Java.

2. Breve resumo

Sempre que desenvolvemos APIs precisamos transitar os dados de forma consistente desde o recebimento até todo processamento na camada de negócio. Nesse contexto começaremos a falar das DTOs (Data Transfer Objects) e a validação dos dados.

3. O que é um DTO?

DTO é um objeto que usamos para transferir dados entre a camada de apresentação (front-end ou consumidores da API) e a camada de negócios, onde de fato o processamento ocorre.

Por exemplo. ao receber uma requisição para cadastrar um novo cliente, com login e senha, você jamais vai passar diretamente o objeto da entidade (modelo) diretamente para camada de controle. Ao invés disso, você criará uma DTO que definirá os dados e como eles serão validados. Parece confuso, mas chegaremos ao código que é muito mais simples do que pensamos.

💡
Mas por que devo validar o corpo da requisição? Quando alguém envia dados para sua API, como um formulário ou um corpo JSON, você precisa garantir que os dados estão chegando exatamente como o sistema precisa. Dessa forma sua aplicação não processará informações erradas e não causará erros ou falhas inesperadas.

4. Vamos ao código

Para facilitar usaremos a biblioteca Lombok para reduzir o código boilerplate (código repetitivo e desnecessário) gerando automaticamente getters/setters.

4.1. Criação da DTO

import lombok.Data;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Size;

@Data
public class LoginDTO {

    @NotEmpty(message = "Preencha o campo e-mail.")
    @Email(message = "Digite um e-mail válido.")
    private String email;

    @Size(min = 6, max = 20, message = "A senha deve ter pelo menos 6 caracteres e no máximo 20.")
    private String password;

}

Nesse exemplo vamos considerar que os dados que estamos recebendo serão usados para logar em um sistema. Usaremos validações como @NotEmpty, @Email e @Size, que são fornecidas pelo Spring para podermos validar que os dados estão no formato correto. A anotação @Data é da biblioteca Lombok para gerar os getters/setters automaticamente.

4.2. Configuração do Controlador (Controller)

import <SEU NAMESPACE>.features.Login.DTO.LoginDTO;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import org.springframework.http.MediaType;

@RestController
public class LoginController {

    @PostMapping(value = "/auth", produces = MediaType.APPLICATION_JSON_VALUE)
    public String auth(@Valid @RequestBody LoginDTO loginDTO) {
        return "Usuário autenticado com sucesso!";
    }

}

Perceba que a anotação chave aqui é @Valid aplicada ao LoginDTO no método auth. Quando o Spring receber a requisição, automaticamente validará os dados que vierem no corpo da requisição com as anotações definidas na DTO. Caso algum dado seja inválido, um BAD REQUEST (400) será gerado como resposta a requisição (exemplo abaixo).

{
  "timestamp": "2025-03-10T12:34:56.789+00:00",
  "status": 400,
  "error": "Bad Request",
  "errors": [
    {
      "field": "email",
      "message": "Digite um e-mail válido."
    },
    {
      "field": "password",
      "message": "A senha deve ter pelo menos 6 caracteres e no máximo 20."
    }
  ],
  "path": "/auth"
}

4.3. Personalizando o retorno de erro

Você pode personalizar esse retorno de acordo com as necessidades da sua aplicação. Veja como é simples.

import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ControllerAdvice
public class DataErrHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<Map<String, List<String>>> handleValidationExceptions(MethodArgumentNotValidException ex) {
        List<String> errors = ex.getFieldErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .toList();
        return ResponseEntity.badRequest().body(Map.of("errors", errors));
    }

}

Nesse caso eu optei em trazer um JSON com um array de erros.

{
  "errors": [
    "Digite um e-mail válido.",
    "A senha deve ter pelo menos 6 caracteres e no máximo 20."
  ]
}

5. Conclusão

O Spring Boot possui muitas funcionalidades já abstraídas que facilita o dia a dia do desenvolvedor. No artigo em tela, verifica-se que o retorno padrão 400 atende a maioria das aplicações para validação de dados. Caso precise adaptar e customizar o retorno, a implementação é bem simples.