Ao desenvolver APIs HTTP, o tratamento de erros costuma ser uma parte trabalhosa. À medida que o número de APIs cresce e a lógica interna fica mais complexa, surgem dificuldades em três aspectos.
- Retornar códigos de erro apropriados: para desenvolvedores com menos experiência, é difícil usar códigos de status HTTP consistentes em lógicas complexas.
- Escrever uma grande quantidade de logs de resultado: registrar logs em todos os pontos de saída esperados quando um erro ocorre aumenta o volume de código e torna a manutenção mais complexa.
- Enviar mensagens de erro claras: apenas repassar uma mensagem de erro ao cliente não é suficiente para entender e tratar o erro com clareza.
Melhorando o retorno de códigos de erro apropriados
Para resolver o problema de consistência no uso de códigos de erro, propõe-se implementar uma interface ou struct HttpError que inclua StatusCode e Message.
- Solução:
- Definir o tipo
HttpError: encapsula o código de status HTTP e a mensagem. - Fornecer funções helper: usar helpers que retornam códigos de erro específicos, como
httperror.BadRequest("wrong format"), para criar objetos de erro com facilidade.
- Definir o tipo
- Vantagens:
- Aproveitar o autocompletar da IDE para inserir códigos de erro e mensagens de forma prática e segura.
- Redução da possibilidade de erro em comparação com digitar códigos numéricos manualmente.
- Menos incômodo ao ter de consultar repetidamente documentos de design preparados com antecedência.
Centralização da escrita de logs
Para reduzir a escrita repetitiva de logs e gerenciar a lógica de tratamento de erros em um só lugar, é apresentado um método de encapsular o handler HTTP.
- Solução:
- Implementar um roteador customizado (
chiwrap.Router): inclui internamente um roteador existente, comochi.Router, e adiciona lógica de tratamento de erros. - Encapsular handlers: métodos como
Getdo roteador customizado recebemHandlerFunc, executam internamente e, se ocorrer um erro, o encaminham para a lógica central de tratamento. - Função de callback de erro: ao criar
NewRouter, recebe-se uma funçãoerrCallback; quando ocorre um erro, essa callback é chamada para registrar logs de forma centralizada ou executar processamento adicional.
- Implementar um roteador customizado (
- Vantagens:
- Quando ocorre um erro na lógica da API, o código de erro e a mensagem apropriados são retornados automaticamente na resposta.
- Fica fácil gerenciar logs ao registrar funções de callback para gravar logs adequados a cada serviço.
- Redução de duplicação de código e melhoria da manutenibilidade.
Envio de mensagens de erro claras (uso do RFC7807)
Para que o cliente possa entender e tratar erros com mais clareza, propõe-se o envio de mensagens de erro estruturadas com base no padrão RFC7807.
- Principais elementos do RFC7807:
type: URI que identifica o tipo de erro (ex.:https://example.com/errors/validation).title: descrição curta do erro em uma linha.status: igual ao código de status HTTP.detail: descrição detalhada do erro, legível por humanos.instance: URI específica em que o erro ocorreu (ex.:/api/users/abc).extensions: objeto JSON que contém informações adicionais (ex.:invalid_field,expected_format).
- Implementação:
-
Criar uma struct
RFC7807Errore incluir os principais elementos. -
Criar facilmente objetos de erro estruturados por meio do padrão de method chaining (
WithType(),WithInstance(),WithExtension()). -
Com o método
ToHttpError(), converterRFC7807ErroremHttpError, permitindo integração com o roteador centralizado. -
O cliente pode identificar com clareza o tipo, a causa e o local de ocorrência do erro.
-
Aumenta a consistência e a utilidade das respostas da API, melhorando a eficiência do desenvolvimento no cliente.
-
5 comentários
Obrigado pelo ótimo artigo.
Ótimo artigo, obrigado!
Só como referência, no Spring existe uma implementação em
org.springframework.http.ProblemDetail, dentro da bibliotecaspring-web!Obrigado pela ótima introdução!
Fui pesquisar e vi que foi substituído pelo RFC 9457.
https://datatracker.ietf.org/doc/html/rfc9457
(documento 7807 anterior: https://datatracker.ietf.org/doc/html/rfc7807)
Principais diferenças entre a RFC 7807 e a RFC 9457
errorsdentro de um único tipo de problemapointerPara novos projetos desde julho de 2023, recomenda-se aplicar a RFC 9457
Parece que é recomendado definir o campo
typecomo uma URI que possa ser dereferenciada.Em serviços internos, provavelmente não há problema em substituí-la por um link para a documentação do Swagger UI.