API REST bem desenhada: contratos, erros e evolução

Uma API boa não é apenas um conjunto de endpoints. É um contrato previsível entre sistemas que continuará funcionando quando ambos evoluírem.

Esta API funciona, mas ninguém sabe exatamente como Considere uma API fictícia para gerenciamento de pedidos. Ela possui estes endpoints: Em caso de sucesso, retorna: Em caso de erro: A API pode funcionar para a primeira interface que a utiliza. O problema aparece quando outro sistema precisa integrá la: qual método apenas consulta; qual operação pode ser repetida; quais campos são obrigatórios; quais erros podem ocorrer; como paginar; como saber se o pedido não existe; quem pode alterar cada recurso; como o contrato evoluirá. Uma API REST bem desenhada reduz essas ambiguidades usando a semântica de HTTP, modelos explícitos e regras consistentes. REST é um estilo arquitetural, não uma lista de nomes obrigatórios. Este artigo concentra se em APIs HTTP orientadas a recursos, frequentemente chamadas de REST APIs. Comece pelo recurso, não pelo verbo na URL Em vez de: use recursos: O verbo fica no método HTTP. A URL identifica o recurso. A RFC 9110 define a semântica compartilhada por HTTP/1.1, HTTP/2 e HTTP/3. Métodos não são intercambiáveis GET Deve recuperar uma representação sem solicitar alteração do estado do recurso. POST Pode criar um recurso ou pedir que o servidor processe a representação conforme a semântica do endpoint. PUT Normalmente cria ou substitui a representação do recurso identificado. PATCH Aplica modificações parciais. DELETE Solicita a remoção da associação do recurso identificado. Usar GET para apagar dados viola expectativas de segurança, cache, rastreamento e ferramentas intermediárias. Modele o ciclo de vida do recurso Um pedido pode possuir estados: Nem toda transição é válida. Um endpoint genérico que permite alterar qualquer campo: com: pode expor alterações que deveriam ser controladas. Em alguns casos, ações explícitas representam melhor a regra: Isso não é uma violação automática do modelo orientado a recursos. Cancelamento, pagamento e envio também podem ser tratados como recursos ou operações de domínio. O importante é tornar: pré condições; efeitos; permissões; idempotência; respostas; visíveis no contrato. Defina schemas de entrada e saída Criação: Resposta: Decisões que precisam ser documentadas: IDs; datas e fuso; precisão monetária; campos opcionais; valores nulos; enumerações; formatos; limites; campos somente leitura; campos obsoletos. Não use ponto flutuante binário sem considerar precisão para valores monetários. Uma API pode optar por string decimal ou unidades inteiras, desde que a convenção seja explícita. Validação possui camadas Estrutural JSON válido; tipo correto; campo obrigatório; tamanho; formato. Semântica produto existe; quantidade está disponível; endereço pertence ao cliente; cupom pode ser usado; estado permite a operação. Autorização identidade pode executar a ação; identidade pode agir sobre aquele recurso; campos alterados estão permitidos; operação respeita escopo e função. Validar que o ID é bem formatado não significa que o usuário pode acessar o objeto. A edição de 2023 do OWASP API Security Top 10 mantém Broken Object Level Authorization como risco central: cada operação que acessa uma fonte de dados por identificador precisa verificar autorização sobre o objeto. Use a semântica de status HTTP Situação Status possível Recurso criado 201 Requisição concluída sem corpo 204 Entrada sintaticamente inválida 400 Credencial ausente ou inválida 401 Identidade sem permissão 403 Recurso não encontrado 404 Conflito com estado atual 409 Pré condição falhou 412 Conteúdo válido, mas semanticamente rejeitado 422 Limite de requisições 429 Erro interno inesperado 500 Dependência temporariamente indisponível 503 Não transforme todos os erros em 200 OK . Resposta problemática: Intermediários, SDKs, métricas e clientes passam a interpretar uma falha como sucesso HTTP. Erros precisam ser úteis e estáveis A RFC 9457 define o formato Problem Details para APIs HTTP e substitui a RFC 7807. Exemplo: Boas propriedades de erro: código legível por máquina; mensagem compreensível; status coerente; referência de correlação; detalhes apenas quando seguros; estrutura consistente. Não envie: stack trace; consulta SQL; segredo; caminho interno; configuração; dados de outro usuário. Não confunda autenticação com autorização Fluxo: Uma API multiempresa também precisa verificar o tenant em toda consulta relevante. Exemplo perigoso: Exemplo com escopo: A consulta não substitui a política de autorização, mas pode reforçar o isolamento. Paginação precisa de contrato Endpoint sem paginação: funciona com 50 registros e degrada com 500 mil. Paginação por página Simples, mas registros inseridos ou removidos durante a navegação podem produzir duplicidade ou ausência. Offset Tem limitações semelhantes e pode ficar caro em grandes conjuntos. Cursor Pode oferecer navegação mais estável, mas exige contrato sobre ordenação e expiração. Resposta: Defina: limite padrão; limite máximo; ordenação; estabilidade; filtros; formato dos links ou cursores; comportamento de cursor inválido. Não exponha necessariamente a implementação interna no cursor. Ele pode ser opaco para permitir evolução. Filtros e ordenação devem ser permitidos explicitamente Exemplo: Não transforme parâmetros diretamente em SQL. Crie uma lista de campos permitidos: Depois valide a direção e aplique parâmetros. Isso reduz injeção, consultas acidentais e dependência da estrutura interna do banco. Idempotência evita duplicidade Uma operação idempotente pode ser repetida e produzir o mesmo efeito pretendido. GET, PUT e DELETE possuem semânticas idempotentes na especificação, embora detalhes da resposta possam variar. POST normalmente não é idempotente. Em pagamentos ou criação de pedidos, o cliente pode não saber se a primeira requisição foi concluída antes da conexão cair. Uma chave de idempotência ajuda: O servidor associa a chave, a identidade e o conteúdo à operação original. Uma repetição compatível retorna o resultado anterior em vez de cobrar novamente. Defina: escopo da chave; retenção; comportamento para corpo diferente; concorrência; armazenamento; códigos de resposta. Concorrência precisa ser tratada Dois clientes podem ler a mesma versão e enviar alterações conflitantes. Uma abordagem usa ETag : Atualização condicional: Se o recurso mudou, o servidor pode responder: Isso evita sobrescrever silenciosamente alterações posteriores. Documente o contrato de forma executável A OpenAPI Specification fornece uma descrição formal e independente de linguagem para APIs HTTP. A página oficial listava a versão 3.2.0 como a mais recente em 15/07/2026. Trecho reduzido: A especificação pode apoiar: documentação; validação; geração de clientes; mocks; testes de contrato; revisão; inventário. Um arquivo OpenAPI desatualizado pode ser pior do que nenhum, porque oferece confiança falsa. Valide a implementação contra o contrato no pipeline de CI/CD. Evolua de forma compatível Mudanças geralmente compatíveis: adicionar endpoint; adicionar campo opcional; adicionar enumeração somente quando consumidores toleram valores desconhecidos; adicionar operação; ampliar documentação. Mudanças potencialmente incompatíveis: remover campo; tornar campo opcional obrigatório; alterar tipo; mudar semântica; renomear propriedade; trocar formato de data; reduzir limite; alterar autorização; mudar ordenação padrão. Mesmo uma adição pode quebrar clientes rígidos. Testes de contrato e comunicação continuam necessários. Estratégias Evolução aditiva Preferível quando mudanças podem ser incorporadas sem quebrar consumidores. Versionamento na URL Visível, mas pode duplicar estruturas e incentivar versões longamente mantidas. Versionamento por mídia ou cabeçalho Mais flexível, porém aumenta complexidade de documentação e infraestrutura. Não versionar cada alteração. Use uma nova versão quando o contrato realmente não puder evoluir de forma compatível. Depreciação precisa de prazo Uma política deve definir: 1. anúncio; 2. data de descontinuação; 3. substituição; 4. consumidores afetados; 5. telemetria de uso; 6. suporte à migração; 7. retirada. Não desligue uma versão apenas porque “ninguém respondeu”. Confirme o uso por logs, chaves, clientes e comunicação. Rate limiting deve proteger sem esconder capacidade insuficiente Limites reduzem abuso e consumo descontrolado. Resposta: Critérios possíveis: identidade; token; organização; IP; operação; custo; janela. Um endpoint de relatório pesado pode consumir mais cota do que uma consulta simples. Rate limiting não corrige consulta ineficiente. Também não deve bloquear usuários legítimos sem observabilidade e suporte. Checklist de revisão Contrato [ ] Recursos possuem nomes coerentes. [ ] Métodos respeitam semântica HTTP. [ ] Schemas estão documentados. [ ] Datas, valores e IDs possuem formato definido. [ ] Erros são estáveis. [ ] OpenAPI acompanha a implementação. Segurança [ ] Autenticação é validada. [ ] Autorização existe por operação e objeto. [ ] Campos alteráveis são permitidos explicitamente. [ ] Entrada possui limites. [ ] Respostas não expõem dados indevidos. [ ] Rate limits e logs estão definidos. Operação [ ] Paginação existe. [ ] Timeouts são conhecidos. [ ] Idempotência foi avaliada. [ ] Concorrência foi avaliada. [ ] Métricas e correlação existem. [ ] Dependências e falhas externas são tratadas. Evolução [ ] Compatibilidade é testada. [ ] Depreciação possui política. [ ] Consumidores são inventariados. [ ] Mudanças possuem documentação. [ ] Versões antigas possuem data de encerramento. Uma API bem desenhada não elimina todas as decisões do cliente. Ela elimina decisões acidentais. Quem consome o serviço deve saber o que enviar, o que receber, como reagir a falhas e por quanto tempo o contrato permanecerá válido.