Se você está desenvolvendo um projeto com Spring Boot e quer uma documentação automática e interativa da sua API, o Swagger com Springdoc OpenAPI é uma excelente escolha.
Neste artigo, vamos mostrar:
- Como adicionar o Swagger ao projeto
- Como corrigir incompatibilidades com o Spring Boot 3.4+
- Como anotar seus endpoints
- Como manter o DTO unificado para entrada e saída
- Como validar os campos obrigatórios
- Como garantir que os exemplos no Swagger reflitam os testes reais
🔧 Adicionando o Swagger ao projeto
Utilizamos a dependência recomendada do Springdoc:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
⚠️ Atenção à versão do Spring Boot!
Se você estiver usando a versão 3.4.x, ocorrerá o seguinte erro:
java.lang.NoSuchMethodError: 'void org.springframework.web.method.ControllerAdviceBean.<init>(java.lang.Object)'
💡 Solução: Utilize o Spring Boot 3.2.5 para garantir compatibilidade.
🌐 Acessando a documentação interativa
Após subir a aplicação (localhost:8080
), acesse:
http://localhost:8080/swagger-ui.html
Você verá todos os endpoints organizados com base nas anotações da sua aplicação.
📦 DTO único para entrada e saída
Utilizamos o mesmo DTO (ProdutoDTO
) tanto para criação quanto para leitura de produtos. Isso simplifica o código e mantém a documentação clara.
Exemplo de JSON usado na criação:
{
"nome": "Casa de Alqueria D.O. Valle Central Carménère 2024",
"preco": 42.50,
"descricao": "Vinho chileno estruturado, ideal para jantares.",
"imgUrl": "",
"categorias": [
{ "id": 1 },
{ "id": 5 }
]
}
✅ Validando os campos obrigatórios
Adicionamos anotações de validação no DTO para garantir que os dados obrigatórios sejam respeitados:
@NotBlank(message = "Nome é obrigatório")
private String nome;
@NotNull(message = "Preço é obrigatório")
@Positive(message = "Preço deve ser maior que zero")
private Double preco;
@NotBlank(message = "Descrição é obrigatória")
private String descricao;
@NotEmpty(message = "Informe ao menos uma categoria")
private List<CategoriaDTO> categorias;
🔄 Método copyDtoToProduto
No serviço, garantimos que ao salvar ou atualizar, as categorias sejam carregadas corretamente com base nos IDs:
private void copyDtoToProduto(ProdutoDTO dto, Produto entity) {
entity.setNome(dto.getNome());
entity.setDescricao(dto.getDescricao());
entity.setPreco(dto.getPreco());
entity.setImgUrl(dto.getImgUrl());
entity.getCategorias().clear();
for (CategoriaDTO catDto : dto.getCategorias()) {
Categoria categoria = categoriaRepository.getReferenceById(catDto.getId());
entity.getCategorias().add(categoria);
}
}
📑 Anotações Swagger nos endpoints
Exemplo de documentação:

🛠 Tratamento de erros
Criamos um @ControllerAdvice
para capturar exceções de validação e exibir erros amigáveis:
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationError> handleValidationErrors(MethodArgumentNotValidException e, HttpServletRequest request) {
ValidationError err = new ValidationError(Instant.now(), 422, "Erro de validação", e.getMessage(), request.getRequestURI());
for (FieldError f : e.getBindingResult().getFieldErrors()) {
err.addError(f.getField(), f.getDefaultMessage());
}
return ResponseEntity.unprocessableEntity().body(err);
}
🎯 Conclusão
Com as práticas que mostramos neste artigo, você garante:
- Documentação atualizada automaticamente
- Validações robustas no backend
- Exemplos coerentes com a realidade no Swagger
- Facilidade de teste para equipes frontend
📺 Vídeo tutorial
Complementamos este conteúdo com um vídeo prático no canal do YouTube KaneChanDev: https://youtu.be/iMMm93r_baI