Padronização de Respostas de Erro em APIs com RFC-9457: Implementando no Spring Framework
Tags: java, errors, api, spring
Published: 2024-06-26 04:24:40

No desenvolvimento de APIs, a clareza e consistência na comunicação de erros são cruciais para a eficiência e a experiência positiva dos desenvolvedores. 

Imagine uma situação onde, ao integrar com uma API, você recebe mensagens de erro confusas ou inconsistentes, dificultando a identificação e correção dos problemas. A especificação RFC-9457 surge como uma solução para padronizar a representação de erros em APIs web, fornecendo uma estrutura clara e uniforme para relatar problemas.

Neste artigo, vamos explorar como implementar o tratamento de erros no Spring Web seguindo a especificação RFC-9457. Veremos desde a configuração inicial até exemplos práticos, demonstrando como essa abordagem pode melhorar significativamente a experiência de desenvolvimento e integração de APIs. Se você busca tornar suas APIs mais robustas e amigáveis, continue lendo para descobrir como a RFC-9457 pode ser um diferencial no seu projeto.

**O que é a RFC-9457?**
A RFC-9457 é uma especificação que define um formato padronizado para a representação de erros em APIs web. Seu objetivo é fornecer uma maneira consistente de informar os clientes sobre problemas ocorridos durante o processamento de suas requisições, melhorando assim a experiência do desenvolvedor e facilitando a integração entre sistemas.

**Estrutura de um Erro Segundo a RFC-9457**
De acordo com a RFC-9457, um erro deve ser representado como um objeto JSON com os seguintes campos:

**type** (Tipo):
Descrição: Uma referência URI que identifica o tipo de problema. O objetivo é fornecer as pessoas que utilizam a API um local para encontrar mais informações sobre o erro específico.
Exemplo: Se o tipo for "https://es.wiktionary.org/wiki/removido", o desenvolvedor pode clicar nesse link para obter detalhes sobre o erro "404 Não Encontrado".
Observação: Se o campo type estiver ausente ou não for aplicável, presume-se que seja "about:blank".

**status** (Status):
Descrição: O código de status HTTP gerado pelo servidor de origem para essa ocorrência do problema.
Objetivo: Informar ao desenvolvedor o tipo de erro HTTP que ocorreu.
Exemplo: Se o status for 404, isso indica que o recurso solicitado não foi encontrado.
Observação: Cada código de status HTTP tem um significado específico definido nas especificações HTTP.

**title** (Título):
Descrição: Um resumo curto e legível do tipo de problema.
Objetivo: Descrever o problema de forma concisa e compreensível para humanos.
Exemplo: O título pode ser "Recurso não encontrado" ou "Falha na autenticação".
Observação: O título deve ser consistente para o mesmo tipo de problema, mesmo em diferentes ocorrências.

**detail** (Detalhe):
Descrição: Uma explicação legível específica para essa ocorrência do problema.
Objetivo: Fornecer ao desenvolvedor mais informações sobre o problema, como a causa ou os parâmetros inválidos.
Exemplo: O detalhe pode ser "O arquivo solicitado não existe" ou "A senha fornecida está incorreta".
Observação: O conteúdo do campo detail pode variar de acordo com a ocorrência do problema.

**instance** (Instância):
Descrição: Uma referência URI que identifica a ocorrência específica do problema.
Objetivo: Fornecer ao desenvolvedor um link para mais informações sobre essa ocorrência específica do problema.
Exemplo: A instância pode ser "https://es.wiktionary.org/wiki/removido", que aponta para a documentação de erro específica para o usuário com ID 123.
Observação: A instância pode ou não fornecer mais informações quando desreferenciada.

**Extensions** (Extensões)
Descrição: Campos adicionais que podem ser incluídos para fornecer informações ou contexto extras aos clientes.
Objetivo: Permitir que APIs definam campos personalizados para comunicar informações específicas do problema.
Exemplo: Uma extensão pode ser "correlationId", que fornece um identificador exclusivo para rastrear a ocorrência do problema.
Observação: As extensões devem ser usadas com cuidado para evitar expor informações confidenciais.

Exemplo de um erro representado segundo a RFC-9457:

![PostmanImagem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wppcyw8x3t7g8m4xhzh5.png)

A partir do spring framework 6 e springboot 3, você consegue utilizar esse padrão de uma forma muito simples:

Para isso basta escolher entre inserir esse argumento no seu application.properties:
`spring.mvc.problemdetails.enabled=true`

Ao fazer isso o erro sai disso:

![PostmanImagem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d1zgx7y4mus31kmt65e8.png)


Para isso:

![PostmanImagem](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aucxifj820jl6kwnkl86.png)

Ou utilizar a extensão: ResponseEntityExceptionHandler na sua classe de GlobalExceptionHandler, um exemplo abaixo:


![GlobalException](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1tp1q9twxrgthywoff5c.png)

Desta forma você consegue personalizar o erro de uma melhor maneira, como o exemplo abaixo:


![REfinamentoErro](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ex97mockckadqz29ojh5.png)

Outro ponto interessante de extender a classe ResponseEntityExceptionHandler é poder fazer o override dos métodos existentes dentro dela, personalizando conforme desejar:

Exemplo ao ativar o RFC-9457 no código ao utilizar um método HTTP não mapeado ocorreria o erro abaixo:


![ErrorMapeamento](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9dorjkyxwdpb92xphkw6.png)

Como pode verificar quase todos os campos, são preenchidos mas, o campo "type" por não possuir um value, acaba ficando em branco, no caso blank, uma das formas de corrigir isto seria utilizar o polimorfismo e sobrescrever o método herdado, conforme imagem abaixo:

![MapeamentoPersonalizado](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3qt79fbezjjdqmmwdu6d.png)


Ao fazer esta alteração, a saída do código de erro se torna mais clara para o usuário final:


![ErroPersonalizadoPostman](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u88m29m2b3rkny1ot7g7.png)

**Benefícios de Usar a RFC-9457**
_Consistência:_ Utilizar um formato padronizado para erros facilita a integração entre diferentes sistemas e a compreensão dos problemas.

_Clareza:_ Mensagens de erro bem definidas ajudam os desenvolvedores a entender rapidamente o que deu errado e como resolver.

_Documentação_: A estrutura clara e consistente facilita a documentação automática e a comunicação com consumidores da API.

**Conclusão**
Adotar a especificação RFC-9457 para o tratamento de erros no Spring não só melhora a consistência e clareza das mensagens de erro, mas também eleva a qualidade geral da sua API. Através da padronização, desenvolvedores podem facilmente entender e solucionar problemas, resultando em uma integração mais eficiente e uma experiência de desenvolvimento mais suave.

Ao seguir as diretrizes da RFC-9457 e implementar as práticas e exemplos discutidos neste artigo, você estará construindo uma API que é mais robusta, transparente e fácil de manter. A clareza nas mensagens de erro não apenas ajuda na resolução de problemas, mas também facilita a documentação e a comunicação com os consumidores da API.

Em um cenário onde a interoperabilidade e a experiência do usuário são cruciais, investir no tratamento de erros conforme a RFC-9457 é um passo estratégico que agrega valor significativo ao seu projeto, tornando suas APIs mais confiáveis e amigáveis para os desenvolvedores.


**_Repositório do código usado no exemplo_**: {% embed https://github.com/diegoSbrandao/RFC-9457-Problem-Details-for-HTTP-APIs.git %}


**Referências Bibliográficas:**
Spring Framework - Respostas de erro: https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-rest-exceptions.html

RFC 9457: Detalhes do Problema para APIs HTTP: https://www.rfc-editor.org/rfc/rfc9457.html

Problem Details (RFC 9457): Doing API Errors Well
https://swagger.io/blog/problem-details-rfc9457-doing-api-errors-well/

Problem Details (RFC 9457): Getting Hands-On with API Error Handling
https://swagger.io/blog/problem-details-rfc9457-api-error-handling/

IANA - Tipos de Problema HTTP: https://www.iana.org/assignments/http-problem-types

Problem Registry - Propriedade de Corpo Ausente: https://community.smartbear.com/discussions/-/Error-103-0x80020006-Unknown-name-Count-while-working-with/-/replies/124624