Software · Desenvolvimento Web & Stacks

Design de APIs RESTful: Contratos OpenAPI, Idempotência e Padronização com RFC 7807

Como projetar contratos de API previsíveis, utilizar códigos de status HTTP com fidelidade semântica e padronizar respostas de erro com a especificação Problem Details.

Diagrama de design de APIs RESTful ilustrando métodos HTTP códigos de status 2xx 4xx 5xx e estrutura JSON de Problem Details RFC 7807

Em arquiteturas orientadas a serviços e microsserviços, a interface de programação de aplicações (API) é o produto fundamental de uma equipe de engenharia. Enquanto o código interno de um serviço pode ser refatorado ou até mesmo reescrito sem impacto externo, o contrato público de uma API vincula clientes web, aplicativos móveis e sistemas de parceiros corporativos. Mudar arbitrariamente uma rota, alterar a semântica de um código HTTP ou retornar erros desestruturados quebra integrações em produção e gera custos operacionais astronômicos.

O bom design de APIs RESTful não é uma questão puramente cosmética de nomenclatura de URLs. Ele estabelece uma linguagem universal, rigorosa e autodocumentada baseada no protocolo HTTP, garantindo previsibilidade através de contratos OpenAPI, comportamento seguro com idempotência e respostas de erro uniformes sob a especificação RFC 7807 (Problem Details).

O Modelo de Maturidade de Richardson e Recursos REST

O modelo formalizado por Leonard Richardson classifica o grau de conformidade de uma API com os princípios arquiteturais da Web em quatro níveis sucessivos:

graph BT
    N0["<b>Nível 0: O Pântano de POX / RPC</b><br/>Endpoint único via POST, túnel de métodos arbitrários"]
    N1["<b>Nível 1: Recursos em URIs</b><br/>Identificadores substantivos plurais para cada entidade"]
    N2["<b>Nível 2: Verbos HTTP + Status Codes</b><br/>GET, POST, PUT, DELETE, PATCH com códigos reais"]
    N3["<b>Nível 3: Hipermídia (HATEOAS)</b><br/>Navegabilidade de estados dirigida por links dinâmicos"]

    N0 --> N1 --> N2 --> N3

    classDef lvl0 fill:#1f131a,stroke:#f43f5e,stroke-width:1px,color:#f8fafc;
    classDef lvl1 fill:#1a1926,stroke:#fbbf24,stroke-width:1px,color:#f8fafc;
    classDef lvl2 fill:#132338,stroke:#38bdf8,stroke-width:2px,color:#f8fafc;
    classDef lvl3 fill:#0f2724,stroke:#34d399,stroke-width:1px,color:#f8fafc;

    class N0 lvl0;
    class N1 lvl1;
    class N2 lvl2;
    class N3 lvl3;

A grande maioria das APIs corporativas de alto padrão opera no Nível 2, combinando recursos substantivos plurais com a rica gramática dos verbos do protocolo HTTP:

  • Substantivos em vez de Verbos na URL: Em vez de expor rotas imperativas como /api/criarCliente ou /api/obterPedidosPorUsuario, a URI representa um recurso no plural: /api/customers e /api/customers/{id}/orders.
  • Mapeamento Estrito de Métodos HTTP:
    • GET: Leitura segura e idempotente de recursos. Nunca deve provocar efeitos colaterais de escrita no banco de dados.
    • POST: Criação de novo recurso subordinado ou execução de processamentos assíncronos não idempotentes.
    • PUT: Substituição completa de um recurso existente no identificador especificado (idempotente).
    • PATCH: Modificação parcial atômica de campos específicos de um recurso.
    • DELETE: Exclusão lógica ou física do recurso identificado (idempotente).

Idempotência e Chaves de Idempotência (Idempotency-Key)

Uma operação é classificada como idempotente quando executá-la múltiplas vezes produz exatamente o mesmo resultado final no estado do sistema que uma única execução bem-sucedida.

  • GET, PUT e DELETE são inerentemente idempotentes segundo a especificação HTTP. Deletar o recurso com ID 123 pela primeira vez remove a linha do banco; deletá-lo novamente retorna que o recurso já não existe (404 Not Found ou 204 No Content), sem corromper outros dados.
  • O método POST, por outro lado, não é idempotente por padrão. Se um cliente móvel disparar uma requisição de pagamento via POST /api/charges e a conexão sem fio oscilar antes do recebimento do pacote de resposta, o cliente reenviará a requisição. Se a API não for protegida contra duplicidade, o cartão do usuário será cobrado duas vezes.

A Solução Corporativa: Cabeçalho Idempotency-Key

Para blindar rotas de mutação sensíveis, implementamos o padrão de chave de idempotência:

  1. O cliente gera um identificador único universal (UUID v4) e o envia no cabeçalho: Idempotency-Key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d.
  2. A API consulta um cache distribuído atômico (como Redis). Se a chave já existir com uma resposta registrada, a API retorna imediatamente o payload anterior em cache sem reprocessar a transação financeira.
  3. Se a chave for nova, o processamento ocorre normalmente e o resultado é salvo com um tempo de vida (TTL) configurado.

Fidelidade Semântica nos Códigos de Status HTTP

Um dos piores anti-patterns da indústria é a chamada "API Anti-HTTP", que retorna 200 OK em todas as situações, acompanhada de um corpo JSON como {"status": "error", "message": "Falha interna"}. Essa prática quebra o funcionamento de proxies reversos, camadas de cache de borda (CDNs) e clientes HTTP automatizados.

Código de Status Significado Semântico Quando Utilizar Corretamente
200 OK Sucesso com payload Resposta de consultas GET, ou PUT/PATCH que retornam a entidade atualizada.
201 Created Recurso criado com sucesso Resposta de POST de criação. Deve incluir o cabeçalho Location: /api/orders/456.
204 No Content Sucesso sem corpo Conclusão de DELETE ou atualizações onde nenhum corpo de resposta precisa ser transmitido.
400 Bad Request Erro de sintaxe na requisição JSON malformado, tipos incompatíveis ou parâmetros obrigatórios ausentes.
401 Unauthorized Não autenticado O cliente não enviou token de autenticação ou o token é inválido/expirado.
403 Forbidden Proibido / Não autorizado O cliente está autenticado com sucesso, mas suas permissões não cobrem o recurso solicitado.
404 Not Found Recurso não localizado A URI informada ou o identificador de entidade não existe no sistema.
409 Conflict Conflito de estado Violação de unicidade (ex: e-mail duplicado) ou falha de concorrência otimista (etag desatualizado).
422 Unprocessable Entity Erro semântico de validação A sintaxe JSON está perfeita, mas regras de negócio falharam (ex: data de início posterior ao término).
429 Too Many Requests Taxa de requisições excedida O cliente atingiu o limite de rate limiting da API. Deve incluir Retry-After.
500 Internal Server Error Falha interna no servidor Exceção não tratada no backend (bug de código ou falha de infraestrutura).

Padronização Universal de Erros com RFC 7807 (Problem Details)

Historicamente, cada empresa inventava seu próprio formato proprietário de erro. O padrão aberto RFC 7807 (Problem Details for HTTP APIs) uniformizou esse ecossistema, definindo um objeto JSON com campos padronizados emitidos com o Content-Type application/problem+json:

{
  "type": "https://api.exemplo.com.br/errors/insufficient-credit",
  "title": "Limite de Crédito Insuficiente",
  "status": 422,
  "detail": "A transação de R$ 1.500,00 excede o saldo disponível de R$ 420,00.",
  "instance": "/api/v1/wallets/w-8821/transactions",
  "invalidParams": [
    {
      "name": "amount",
      "reason": "O valor solicitado ultrapassa o limite pré-aprovado."
    }
  ]
}
  • type: Uma URI que serve como identificador único do tipo de problema, apontando para a documentação técnica do erro.
  • title: Um resumo curto e legível para humanos sobre o problema (não varia de instância para instância).
  • status: O código numérico HTTP correspondente, garantindo alinhamento entre cabeçalho de transporte e payload.
  • detail: A explicação contextual específica para aquela ocorrência.
  • instance: A URI exata da requisição que gerou o erro, facilitando auditoria e correlação com logs de observabilidade.

Diretrizes para APIs em Ambientes Corporativos

Em ecossistemas corporativos escaláveis, o desenvolvimento de APIs costuma seguir o paradigma API-First:

  1. Especificação OpenAPI como Contrato Central: Antes de escrever o código de implementação, as equipes modelam o contrato em OpenAPI 3.1, validando esquemas de dados, tipos estritos e códigos de retorno com os consumidores do serviço.
  2. Pipelines com Suporte a RFC 7807: Aplicações modernas utilizam middlewares globais de Problem Details. Erros de validação do modelo, regras de negócio ou exceções de infraestrutura são encapsulados no formato padrão, evitando a exposição de detalhes internos e stack traces.
  3. Versionamento Semântico e Evolução Suave: A prática recomendada adota versionamento explícito na URI (/api/v1/) para mudanças estruturais incompatíveis. Campos novos podem ser adicionados de forma aditiva, enquanto campos existentes passam por depreciação gradual via cabeçalhos HTTP Sunset e Deprecation antes da remoção.