diff --git a/README.md b/README.md index ca498de..d8dafdb 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,13 @@ No Windows, confirme que o Java está disponível no `PATH` e execute | `PUT` | `/ordens/{id}` | Atualiza uma ordem existente | | `DELETE` | `/ordens/{id}` | Exclui uma ordem existente | +## Respostas de erro + +Erros de validação retornam `400 Bad Request` no formato Problem Details, +incluindo uma propriedade `campos` com as mensagens de cada campo inválido. +Consultas, atualizações ou exclusões de IDs inexistentes retornam +`404 Not Found` no mesmo formato padronizado. + ## Testes Com o Java 21 ou superior configurado, execute: diff --git a/src/main/java/com/exemplo/ordem_servico/exception/ApiExceptionHandler.java b/src/main/java/com/exemplo/ordem_servico/exception/ApiExceptionHandler.java new file mode 100644 index 0000000..da59040 --- /dev/null +++ b/src/main/java/com/exemplo/ordem_servico/exception/ApiExceptionHandler.java @@ -0,0 +1,47 @@ +package com.exemplo.ordem_servico.exception; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.context.support.DefaultMessageSourceResolvable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ApiExceptionHandler { + + @ExceptionHandler(OrdemServicoNaoEncontradaException.class) + public ProblemDetail tratarOrdemNaoEncontrada( + OrdemServicoNaoEncontradaException exception) { + ProblemDetail problema = ProblemDetail.forStatusAndDetail( + HttpStatus.NOT_FOUND, + exception.getMessage()); + problema.setTitle("Ordem de serviço não encontrada"); + return problema; + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ProblemDetail tratarValidacao( + MethodArgumentNotValidException exception) { + Map campos = exception.getBindingResult() + .getFieldErrors() + .stream() + .collect(Collectors.toMap( + FieldError::getField, + DefaultMessageSourceResolvable::getDefaultMessage, + (primeiraMensagem, mensagemRepetida) -> primeiraMensagem, + LinkedHashMap::new)); + + ProblemDetail problema = ProblemDetail.forStatusAndDetail( + HttpStatus.BAD_REQUEST, + "Um ou mais campos possuem valores inválidos."); + problema.setTitle("Dados inválidos"); + problema.setProperty("campos", campos); + return problema; + } +} diff --git a/src/test/java/com/exemplo/ordem_servico/exception/ApiExceptionHandlerTests.java b/src/test/java/com/exemplo/ordem_servico/exception/ApiExceptionHandlerTests.java new file mode 100644 index 0000000..73b0371 --- /dev/null +++ b/src/test/java/com/exemplo/ordem_servico/exception/ApiExceptionHandlerTests.java @@ -0,0 +1,51 @@ +package com.exemplo.ordem_servico.exception; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.validation.BeanPropertyBindingResult; +import org.springframework.validation.FieldError; +import org.springframework.web.bind.MethodArgumentNotValidException; + +class ApiExceptionHandlerTests { + + private final ApiExceptionHandler handler = new ApiExceptionHandler(); + + @Test + void devePadronizarErroDeOrdemNaoEncontrada() { + ProblemDetail problema = handler.tratarOrdemNaoEncontrada( + new OrdemServicoNaoEncontradaException(42L)); + + assertEquals(HttpStatus.NOT_FOUND.value(), problema.getStatus()); + assertEquals("Ordem de serviço não encontrada", problema.getTitle()); + assertEquals( + "Não existe ordem de serviço com o ID 42", + problema.getDetail()); + } + + @Test + void deveInformarCamposComErroDeValidacao() { + Object alvo = new Object(); + BeanPropertyBindingResult resultado = new BeanPropertyBindingResult( + alvo, + "ordemServico"); + resultado.addError(new FieldError( + "ordemServico", + "cliente", + "O nome do cliente é obrigatório!")); + MethodArgumentNotValidException exception = + new MethodArgumentNotValidException(null, resultado); + + ProblemDetail problema = handler.tratarValidacao(exception); + + assertEquals(HttpStatus.BAD_REQUEST.value(), problema.getStatus()); + assertEquals("Dados inválidos", problema.getTitle()); + assertEquals( + Map.of("cliente", "O nome do cliente é obrigatório!"), + problema.getProperties().get("campos")); + } +}