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.
Neste artigo
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/criarClienteou/api/obterPedidosPorUsuario, a URI representa um recurso no plural:/api/customerse/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,PUTeDELETEsão inerentemente idempotentes segundo a especificação HTTP. Deletar o recurso com ID123pela primeira vez remove a linha do banco; deletá-lo novamente retorna que o recurso já não existe (404 Not Foundou204 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 viaPOST /api/chargese 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:
- O cliente gera um identificador único universal (UUID v4) e o envia no cabeçalho:
Idempotency-Key: 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d. - 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.
- 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:
- 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.
- 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.
- 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 HTTPSunseteDeprecationantes da remoção.