RFC 9457 problem json para erros previsíveis

RFC 9457 problem json para erros previsíveis

Uma integração não falha apenas quando o servidor responde com 5xx. Uma assinatura inválida, uma chave de idempotência reutilizada com payload diferente ou um parâmetro de placa malformado também exigem uma resposta que o sistema cliente consiga interpretar sem adivinhação. É esse o papel do RFC 9457 problem json: padronizar a representação de problemas em APIs HTTP.

Para operações que consultam, analisam ou atualizam dados veiculares em escala, erros previsíveis reduzem retrabalho no suporte e evitam decisões erradas na aplicação. O status HTTP informa a categoria do resultado. O corpo `application/problem+json` explica o que ocorreu, em um formato estável e processável.

O que o RFC 9457 define

O RFC 9457 especifica Problem Details for HTTP APIs. Ele atualiza a especificação anterior do mesmo modelo e define uma estrutura JSON para comunicar erros. Não é um catálogo de códigos de negócio, nem substitui o uso correto de status HTTP. Ele estabelece um envelope comum para que diferentes endpoints descrevam falhas com a mesma semântica básica.

O tipo de mídia recomendado é `application/problem+json`. Quando a resposta tem esse `Content-Type`, o consumidor sabe que está diante de uma descrição de problema, e não de uma resposta de sucesso com um campo de erro improvisado.

Os cinco membros padronizados são `type`, `title`, `status`, `detail` e `instance`. Todos têm função distinta. `type` identifica a categoria do problema por meio de uma URI. `title` traz uma descrição curta, voltada à leitura humana. `status` repete o status HTTP no corpo quando isso ajuda o processamento ou o registro da resposta. `detail` explica a ocorrência específica. `instance` identifica aquela ocorrência ou recurso de problema em particular.

Um detalhe relevante: `status` no JSON não é a fonte de verdade para a camada HTTP. Clientes devem decidir o fluxo com base no código da resposta HTTP. A duplicação existe para preservar contexto quando o corpo é armazenado, encaminhado ou analisado fora da resposta original.

Por que problem json melhora uma integração B2B

Em uma API de dados veiculares, o mesmo integrador pode lidar com autenticação, autorização por IP, limites de requisição, consultas por identificador e fluxos assíncronos. Se cada endpoint retornar erros com nomes e formatos próprios, o cliente precisa criar tratamento específico para cada operação. O custo aparece no código, nos alertas e na investigação de incidentes.

Com RFC 9457, o contrato fica mais claro. A aplicação pode ler o status HTTP para escolher entre corrigir uma entrada, renovar credenciais, aguardar uma janela de retentativa ou abrir investigação. Em seguida, usa `type` para classificar a causa sem depender de textos em linguagem natural.

Isso não significa que todo erro deve expor detalhes internos. O `detail` precisa ajudar o integrador, mas não deve revelar segredo de assinatura, regra antifraude, topologia de infraestrutura ou dados que não pertencem ao escopo daquela chamada. Uma mensagem como “assinatura inválida” costuma ser suficiente. Informar qual parte do segredo esperado falhou seria uma exposição desnecessária.

A Lanet utiliza autenticação por HMAC-SHA256, com carimbo de tempo. Esse desenho permite que o servidor valide a integridade e a autoria da requisição sem transportar o segredo em claro. Quando a validação falha, uma resposta de problema bem definida permite distinguir uma assinatura inválida de um timestamp fora da janela aceita, sem transformar a resposta em material de diagnóstico sensível.

Campos que precisam ser estáveis

O maior ganho do padrão vem da estabilidade. Uma equipe pode alterar o texto de `detail` para tornar a mensagem mais clara, mas não deveria mudar o significado de `type` sem versionar o contrato. Se o cliente toma uma ação automática com base em uma categoria, essa categoria precisa permanecer confiável ao longo do tempo.

Considere uma requisição rejeitada porque o header de idempotência não foi enviado em um `POST`:

```http HTTP/1.1 400 Bad Request Content-Type: application/problem+json

{ "type": "https://api.exemplo.com/problems/idempotency-key-required", "title": "Chave de idempotência obrigatória", "status": 400, "detail": "Envie o header Idempotency-Key para esta operação.", "instance": "/v1/consultas/9f2c1a" } ```

O texto atende alguém que está depurando a integração. Já o `type` permite que um SDK, um middleware ou uma rotina interna reconheça a categoria `idempotency-key-required` e registre o evento de forma consistente.

A URI em `type` não precisa ser consultável para cumprir o RFC. Ainda assim, disponibilizar documentação legível nessa URI pode facilitar a operação. Se a URI não tiver documentação pública, ela continua sendo um identificador válido. O ponto é que ela represente um tipo de problema, não uma mensagem arbitrária por ocorrência.

`instance` exige critério. Ele pode apontar para uma URI da requisição, para uma referência de correlação ou para uma página restrita de diagnóstico. Não deve conter CPF, placa, token, segredo ou qualquer dado que aumente o impacto de logs compartilhados. Em muitos casos, um identificador de rastreio também pode ser retornado em um header próprio, desde que a documentação explique como relacioná-lo ao problema.

Status HTTP e tipos de problema devem concordar

O RFC 9457 não corrige o uso inadequado de HTTP. Uma API que devolve `200 OK` para uma credencial rejeitada, com um JSON contendo `erro: true`, dificulta proxy, observabilidade, bibliotecas clientes e políticas de retentativa. O status precisa representar o resultado na camada HTTP.

Erros de entrada normalmente usam `400 Bad Request`. Quando a identidade apresentada não é válida, `401 Unauthorized` é o status apropriado. Quando a identidade é válida, mas não tem permissão para aquela operação, use `403 Forbidden`. Um recurso que não existe no contexto autorizado pode resultar em `404 Not Found`.

Para limites de uso, `429 Too Many Requests` é mais útil do que um `400` genérico. A resposta deve informar quando possível um header `Retry-After`, ou uma política documentada de espera. Para falhas internas inesperadas, `500 Internal Server Error` comunica que o cliente não deve tentar corrigir o payload como primeira ação. Mesmo nesse caso, o corpo problem json pode incluir um identificador de correlação seguro para suporte e auditoria.

Há situações menos óbvias. Uma chave de idempotência já utilizada com exatamente o mesmo método, rota e payload pode levar à reprodução da resposta anterior, conforme a política da API. A mesma chave associada a um payload diferente representa conflito semântico e pode ser tratada como `409 Conflict`. O `type` deve deixar essa diferença explícita, pois a ação do cliente muda: no primeiro caso, ele recupera o resultado conhecido; no segundo, gera uma nova chave após revisar o fluxo.

Extensões para erros de validação

Os cinco campos padronizados raramente bastam para formulários ou payloads complexos. O RFC permite membros de extensão. Eles devem ter nomes que não colidam com campos futuros e uma semântica documentada.

Um padrão útil é incluir uma lista `errors` para apontar falhas por campo:

```json { "type": "https://api.exemplo.com/problems/validation-error", "title": "Dados inválidos", "status": 400, "detail": "Um ou mais campos não passaram na validação.", "errors": [ { "field": "placa", "code": "invalid_format", "message": "Informe a placa no formato aceito pela operação." }, { "field": "callback_url", "code": "invalid_scheme", "message": "A URL de callback deve usar HTTPS." } ] } ```

O campo `code` é mais adequado para automação do que `message`. A mensagem pode ser ajustada por clareza ou idioma. Já `invalid_format` e `invalid_scheme` devem ter significado contratual. Se houver localização de mensagens, ela não pode alterar os códigos nem a estrutura dos dados.

Evite enviar uma pilha de exceções, nome de tabela, consulta interna ou retorno bruto de componente de infraestrutura em extensões. Além de criar acoplamento, esse hábito expõe detalhes que não ajudam o integrador a resolver o problema. Para análise interna, registre evidências no sistema de observabilidade e associe-as ao identificador de correlação.

Como implementar sem criar um contrato frágil

A implementação começa no ponto central de tratamento de exceções. Em vez de cada controller montar uma resposta diferente, a API deve mapear erros conhecidos para status, `type`, título e extensões permitidas. Isso reduz divergência entre endpoints e facilita testes de contrato.

Defina uma taxonomia curta de tipos. Por exemplo, falhas de assinatura, timestamp inválido, IP não autorizado, limite excedido, idempotência ausente, idempotência em conflito, validação de campos e indisponibilidade temporária. A taxonomia deve refletir ações distintas do cliente. Criar um tipo exclusivo para cada frase de erro fragmenta o monitoramento e não traz ganho operacional.

Também vale testar a resposta como parte da interface pública. Verifique o `Content-Type`, o status, os campos obrigatórios, a ausência de dados sensíveis e a estabilidade dos códigos de extensão. Para webhooks, aplique o mesmo princípio ao registrar erros de entrega e ao documentar a estratégia de retentativa. Um erro padronizado não elimina falhas de rede, mas diminui a ambiguidade quando elas acontecem.

O RFC 9457 problem json funciona melhor quando cada tipo de erro leva a uma decisão clara: corrigir a requisição, renovar uma credencial, aguardar, repetir com segurança ou investigar. Esse é o critério prático para avaliar o contrato antes de publicar um novo endpoint.

← Todos os artigos do blog

Fale com o comercial no WhatsApp +55 11 4858-7977