Boas práticas de design de respostas de erro seguindo RFC 7807
1. Fundamentos da RFC 7807 (Problem Details for HTTP APIs)
1.1. Origem e objetivos da especificação
A RFC 7807, publicada em 2016 pelo IETF, estabelece um formato padronizado para representar problemas em APIs HTTP. Seu principal objetivo é eliminar a fragmentação de formatos de erro entre diferentes APIs, proporcionando uma experiência consistente para desenvolvedores e ferramentas de integração.
1.2. Estrutura básica do corpo de resposta
A especificação define cinco campos principais que compõem o corpo da resposta de erro:
{
"type": "https://api.exemplo.com/erros/nao-encontrado",
"title": "Recurso não encontrado",
"status": 404,
"detail": "O usuário com ID 12345 não foi encontrado no sistema.",
"instance": "/api/usuarios/12345"
}
- type: URI que identifica o tipo de problema
- title: Resumo legível do problema
- status: Código HTTP correspondente
- detail: Descrição específica do erro
- instance: URI do recurso onde o erro ocorreu
1.3. Diferenças entre RFC 7807 e formatos proprietários
Diferente de formatos proprietários comuns, a RFC 7807 oferece:
// Formato proprietário (inconsistente)
{
"error": "Usuário não encontrado",
"code": 404
}
// Formato RFC 7807 (padronizado)
{
"type": "https://api.exemplo.com/erros/nao-encontrado",
"title": "Recurso não encontrado",
"status": 404,
"detail": "O usuário com ID 12345 não foi encontrado.",
"instance": "/api/usuarios/12345"
}
2. Mapeamento de Campos Obrigatórios e Opcionais
2.1. Campos obrigatórios
Os campos obrigatórios garantem a consistência mínima das respostas:
{
"type": "https://api.exemplo.com/erros/erro-interno",
"title": "Erro interno do servidor",
"status": 500
}
2.2. Campos recomendados
Para melhor experiência do desenvolvedor, inclua detail e instance:
{
"type": "https://api.exemplo.com/erros/validacao",
"title": "Erro de validação",
"status": 422,
"detail": "O campo 'email' deve conter um endereço de e-mail válido.",
"instance": "/api/usuarios/criar"
}
2.3. Extensões customizadas
Adicione campos específicos do domínio quando necessário:
{
"type": "https://api.exemplo.com/erros/validacao",
"title": "Erro de validação",
"status": 422,
"detail": "Múltiplos campos inválidos.",
"instance": "/api/pedidos/criar",
"errors": [
{
"field": "email",
"message": "Formato de e-mail inválido"
},
{
"field": "telefone",
"message": "Número deve ter 11 dígitos"
}
],
"timestamp": "2024-01-15T10:30:00Z",
"traceId": "abc-123-def-456"
}
3. Estratégias para Definir URIs de type
3.1. Criação de URIs estáveis e documentadas
Utilize URIs que apontem para documentação detalhada:
{
"type": "https://docs.api.exemplo.com/erros/v1/validacao-campo-obrigatorio",
"title": "Campo obrigatório não informado",
"status": 400,
"detail": "O campo 'nome' é obrigatório."
}
3.2. URIs relativas vs. absolutas
Em desenvolvimento, URIs relativas facilitam testes locais:
// Desenvolvimento
"type": "/erros/validacao"
// Produção
"type": "https://api.exemplo.com/erros/v1/validacao"
3.3. Versionamento de problem types
Evolua os tipos sem quebrar clientes existentes:
// Versão 1
"type": "https://api.exemplo.com/erros/v1/validacao"
// Versão 2 (adiciona novos campos)
"type": "https://api.exemplo.com/erros/v2/validacao"
4. Tratamento de Erros de Validação e Erros de Negócio
4.1. Representação de múltiplos erros de validação
{
"type": "https://api.exemplo.com/erros/validacao-multipla",
"title": "Erros de validação múltiplos",
"status": 422,
"detail": "Foram encontrados 3 erros de validação.",
"instance": "/api/produtos/criar",
"errors": [
{
"field": "preco",
"message": "Preço deve ser maior que zero",
"value": -10
},
{
"field": "quantidade",
"message": "Quantidade deve ser inteira",
"value": 1.5
}
]
}
4.2. Uso de detail para mensagens dinâmicas
{
"type": "https://api.exemplo.com/erros/saldo-insuficiente",
"title": "Saldo insuficiente",
"status": 422,
"detail": "Saldo atual: R$ 50,00. Valor necessário: R$ 200,00.",
"instance": "/api/transferencias"
}
4.3. Exemplos práticos: 400 vs. 422
Erro 400 (Bad Request) para problemas de sintaxe:
{
"type": "https://api.exemplo.com/erros/json-invalido",
"title": "JSON inválido",
"status": 400,
"detail": "Erro de parsing na linha 3, coluna 10: caractere inesperado."
}
Erro 422 (Unprocessable Entity) para regras de negócio:
{
"type": "https://api.exemplo.com/erros/limite-credito-excedido",
"title": "Limite de crédito excedido",
"status": 422,
"detail": "O valor da compra (R$ 5.000,00) excede o limite disponível (R$ 3.000,00).",
"instance": "/api/compras"
}
5. Integração com Códigos de Status HTTP e Headers
5.1. Consistência entre status no body e HTTP
O campo status deve corresponder exatamente ao código HTTP:
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
{
"type": "https://api.exemplo.com/erros/nao-encontrado",
"title": "Recurso não encontrado",
"status": 404,
"detail": "Produto com SKU 'ABC-123' não encontrado."
}
5.2. Headers específicos
Content-Type: application/problem+json
5.3. Caching e retry
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 120
Cache-Control: no-store
{
"type": "https://api.exemplo.com/erros/limite-taxa",
"title": "Limite de requisições excedido",
"status": 429,
"detail": "Aguarde 120 segundos antes de realizar novas requisições."
}
6. Boas Práticas para Documentação e Versionamento
6.1. Catálogo centralizado de problem types
Mantenha uma documentação acessível em:
https://docs.api.exemplo.com/erros/
6.2. Versionamento semântico
https://api.exemplo.com/erros/v1/validacao
https://api.exemplo.com/erros/v2/validacao
6.3. OpenAPI + RFC 7807
components:
schemas:
Problema:
type: object
properties:
type:
type: string
format: uri
title:
type: string
status:
type: integer
detail:
type: string
instance:
type: string
format: uri
required:
- type
- title
- status
7. Implementação em Diferentes Linguagens e Frameworks
7.1. Middleware em Node.js (Express)
function errorHandler(err, req, res, next) {
const problema = {
type: 'https://api.exemplo.com/erros/erro-interno',
title: 'Erro interno do servidor',
status: err.status || 500,
detail: err.message || 'Ocorreu um erro inesperado.',
instance: req.originalUrl
};
res.status(problema.status)
.type('application/problem+json')
.json(problema);
}
7.2. Handler em Python (FastAPI)
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(Exception)
async def problem_handler(request: Request, exc: Exception):
return JSONResponse(
status_code=500,
content={
"type": "https://api.exemplo.com/erros/erro-interno",
"title": "Erro interno do servidor",
"status": 500,
"detail": str(exc),
"instance": str(request.url)
},
media_type="application/problem+json"
)
7.3. Adaptação para GraphQL
{
"errors": [
{
"message": "Usuário não encontrado",
"extensions": {
"type": "https://api.exemplo.com/erros/nao-encontrado",
"status": 404,
"detail": "Usuário com ID 12345 não encontrado"
}
}
]
}
8. Monitoramento e Observabilidade de Erros
8.1. Rastreamento com instance
{
"type": "https://api.exemplo.com/erros/pagamento-recusado",
"title": "Pagamento recusado",
"status": 402,
"detail": "Cartão sem fundos suficientes.",
"instance": "/api/pagamentos/transacao-abc-123"
}
8.2. Correlação com OpenTelemetry
{
"type": "https://api.exemplo.com/erros/timeout-banco",
"title": "Timeout na comunicação com banco",
"status": 504,
"detail": "Banco de dados não respondeu em 30 segundos.",
"traceId": "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
}
8.3. Alertas baseados em tipo de problema
Configure alertas para tipos específicos:
Alerta: Erro crítico detectado
Tipo: https://api.exemplo.com/erros/banco-indisponivel
Frequência: 50 ocorrências nos últimos 5 minutos
Status: 503
Referências
- RFC 7807 - Problem Details for HTTP APIs (IETF) — Documentação oficial da especificação que define o formato padronizado para respostas de erro em APIs HTTP.
- Problem Details for HTTP APIs - Guia Prático (Microsoft) — Implementação da RFC 7807 no ecossistema .NET com exemplos práticos.
- FastAPI - Error Handling with RFC 7807 — Tutorial oficial do FastAPI sobre tratamento de erros utilizando o formato Problem Details.
- OpenAPI Specification - Error Responses — Documentação sobre como definir respostas de erro padronizadas em contratos OpenAPI.
- Problem Details for HTTP APIs - Artigo Técnico (Auth0) — Guia completo sobre boas práticas de tratamento de erros em APIs REST, incluindo RFC 7807.
- Express.js Error Handling Middleware — Documentação oficial do Express.js sobre criação de middlewares para tratamento de erros.
- OpenTelemetry - Distributed Tracing — Conceitos de rastreamento distribuído para correlação com respostas de erro.