RFC 9457 em APIs REST: Problem Details como contrato de erro
Como padronizar erro HTTP para melhorar DX, observabilidade e troubleshooting.
Resumo executivo
Como padronizar erro HTTP para melhorar DX, observabilidade e troubleshooting.
Ultima atualizacao: 16/02/2026
Introdução: A assimetria entre sucesso e falha
A maioria das APIs é meticulosamente projetada para o caminho feliz (happy path). Schemas de requisição são validados, modelos de resposta são tipados e status codes de sucesso estão corretos. Mas quando algo dá errado, a qualidade desmorona. Respostas de erro retornam strings cruas, mensagens genéricas como "Algo deu errado" ou — pior — um 200 OK com um campo error escondido dentro do corpo JSON.
Essa assimetria custa caro. Sem um formato de erro estruturado e previsível, cada consumidor da API precisa escrever lógica de tratamento de erro sob medida. Equipes de suporte gastam horas em incidentes porque os logs de erro não contêm contexto acionável. Dashboards de observabilidade não conseguem agregar falhas por categoria porque não existe uma taxonomia padrão.
A RFC 9457 (Problem Details for HTTP APIs) resolve isso definindo um envelope padronizado e legível por máquina para erros de API. Ela transforma a falha de algo improvisado em um contrato de primeira classe.
O padrão RFC 9457: O que ele define
A RFC 9457 especifica um formato de resposta JSON (ou XML) com um conjunto bem definido de campos. O content type é application/problem+json.
Campos principais
json{
"type": "https://api.exemplo.com/erros/saldo-insuficiente",
"title": "Saldo Insuficiente",
"status": 422,
"detail": "A conta 12345 tem saldo de R$ 10,00, mas a transação requer R$ 25,00.",
"instance": "/transferencias/txn-abc-123"
}| Campo | Propósito | Regra Chave |
|---|---|---|
type | Uma URI que identifica unicamente a categoria do problema. | Deve ser estável e referenciável (idealmente linka para documentação ou um runbook). Este é o campo principal para automação. |
title | Um resumo curto e legível do tipo de problema. | Deve ser o mesmo para todas as ocorrências deste type. Não inclua dados específicos da instância aqui. |
status | O status code HTTP (repetido por conveniência). | Deve coincidir com o status code HTTP real da resposta. |
detail | Uma explicação legível específica desta ocorrência. | Aqui vai o contexto específico da instância: IDs de conta, valores, nomes de campos. |
instance | Uma URI identificando a ocorrência específica (para correlação de logs). | Tipicamente o path da requisição ou um ID único de trace/correlação. |
Campos de extensão
A RFC 9457 permite explicitamente campos de extensão customizados. É aqui que você adiciona contexto específico do domínio:
json{
"type": "https://api.exemplo.com/erros/validacao-falhou",
"title": "Validação Falhou",
"status": 422,
"detail": "O corpo da requisição contém 2 erros de validação.",
"instance": "/usuarios/cadastro",
"errors": [
{ "field": "email", "message": "Deve ser um endereço de email válido." },
{ "field": "password", "message": "Deve ter pelo menos 8 caracteres." }
],
"traceId": "abc-def-123-456"
}O array errors e o traceId são extensões customizadas — não definidas pela RFC, mas totalmente em conformidade com ela.
Por que isso importa: Antes e depois
Sem RFC 9457 (erros ad-hoc)
Diferentes endpoints retornam erros em formatos completamente diferentes:
json// Endpoint A
{ "error": "bad request" }
// Endpoint B
{ "code": 1001, "msg": "Email inválido" }
// Endpoint C
{ "success": false, "reason": "Não encontrado" }Cada consumidor da API precisa escrever três estratégias diferentes de parsing de erro. Ferramentas de observabilidade não conseguem agregar esses dados. Equipes de suporte não conseguem fazer triagem eficiente.
Com RFC 9457 (erros padronizados)
Todo endpoint retorna a mesma estrutura. Consumidores escrevem um único handler de erro. Dashboards agregam por type. Equipes de suporte linkam diretamente para runbooks a partir da URI do type.
Aprofundando a análise: Projetando uma taxonomia de erros
A decisão arquitetural de maior impacto ao adotar a RFC 9457 é projetar sua taxonomia de erros — o catálogo de URIs do campo type.
Princípios para uma boa taxonomia
- Nível de domínio, não de código. Os tipos devem representar falhas do domínio de negócio (
saldo-insuficiente,pedido-ja-enviado), e não exceções internas (NullPointerException,SequelizeValidationError). - Estáveis e versionados. Uma vez que uma URI de
typeé publicada, mudar seu significado é uma breaking change para consumidores que automatizam com base nela. - Nunca exponha detalhes internos. O campo
detaildeve ser sanitizado. Nunca vaze stack traces, nomes de tabelas do banco de dados ou nomes de serviços internos em respostas de erro em produção. - Linke para runbooks. Se a URI do
typeé referenciável (ex:https://api.exemplo.com/erros/limite-taxa-excedido), ela deveria retornar uma página legível explicando o erro, causas possíveis e passos para resolução.
Exemplo de estrutura de taxonomia
URI do type | title | status típico |
|---|---|---|
/erros/validacao-falhou | Validação Falhou | 422 |
/erros/recurso-nao-encontrado | Recurso Não Encontrado | 404 |
/erros/saldo-insuficiente | Saldo Insuficiente | 422 |
/erros/limite-taxa-excedido | Limite de Taxa Excedido | 429 |
/erros/conflito-duplicado | Conflito de Recurso Duplicado | 409 |
/erros/nao-autenticado | Autenticação Necessária | 401 |
/erros/sem-permissao | Permissões Insuficientes | 403 |
/erros/servico-indisponivel | Serviço Upstream Indisponível | 503 |
Quando a RFC 9457 acelera a entrega
Padronizar contratos de erro gera retornos compostos em toda a organização:
- Redução de custo de suporte: Times podem automatizar triagem com base no campo
typeem vez de parsear mensagens de texto livre. - Melhoria de observabilidade: Dashboards podem agregar erros por
typeestatus, habilitando análise de tendências (ex: "erros de validação aumentaram 40% após o último deploy"). - Melhoria de DX para consumidores: Novos consumidores da API aprendem um formato de erro, escrevem um handler de erro e confiam que ele funciona consistentemente em todos os endpoints.
Perguntas de decisão para o seu contexto de engenharia:
- Quais classes de erro no seu domínio precisam de identificadores
typeestáveis para automação de consumidores (ex: lógica de retry, mensagens apresentadas ao usuário)? - Como você versionará o catálogo de erros sem quebrar clientes existentes?
- Quais campos de correlação (
traceId,requestId) são obrigatórios para fluxos de suporte e auditoria?
Plano tático de otimização
- Defina uma taxonomia de falhas por domínio. Crie um catálogo documentado de todos os tipos de problema, agrupados por domínio de negócio (Pagamentos, Auth, Catálogo).
- **Padronize
application/problem+jsonglobalmente.** Toda resposta de erro em todas as superfícies da API deve usar este content type. - **Instrumente métricas por
typee endpoint.** Monitore quais tipos de problema ocorrem com maior frequência e em quais endpoints. - Sanitize payloads de erro. Garanta que nenhum nome de exceção interna, stack trace, query SQL ou detalhe de infraestrutura vaze nas respostas de erro em produção.
- Documente exemplos de erro no OpenAPI. A especificação OpenAPI de cada endpoint deve incluir exemplos de respostas
application/problem+jsonpara seus modos de falha esperados. - **Treine consumidores no handling baseado em
type.** Consumidores devem ramificar sua lógica de tratamento de erro no campotype, não em string-matching da mensagemdetail.
Validações de confiabilidade
Meça o sucesso da adoção da RFC 9457 monitorando:
- Tempo médio de diagnóstico por tipo de problema: O tempo para diagnosticar issues diminuiu agora que os erros carregam contexto estruturado?
- Taxa de conformidade RFC 9457: Qual percentual das respostas de erro retorna um envelope
application/problem+jsoncompleto e válido? - Qualidade dos tickets de suporte: Os tickets de suporte diminuíram ou melhoraram em qualidade agora que consumidores recebem contexto técnico acionável?
Quer transformar esse plano em execução com previsibilidade técnica e impacto no negócio? Falar com especialista em web com a Imperialis para desenhar, implementar e operar essa evolução.