Engenharia 1 de fevereiro de 2026 · 6 min de leitura

Projetar APIs Que Duram

As APIs são contratos. Ao contrário do código interno que pode ser refatorado livremente, uma API publicada cria expectativas que são caras de quebrar. Os consumidores constroem aplicações, integrações e processos de negócio em cima da sua API, e cada alteração incompatível força-os a investir tempo e esforço na adaptação. Projetar APIs que duram significa tomar decisões hoje que ainda farão sentido daqui a três anos, mesmo que o sistema evolua significativamente por baixo da superfície.

Design Centrado no Consumidor

O erro de design de API mais comum é construir a API como um wrapper fino à volta do modelo de dados interno. Isto acopla os consumidores aos detalhes da implementação, tornando impossível refatorar os internos sem quebrar a API. Em vez disso, desenhe a API da perspetiva do consumidor: o que precisam de realizar, que informação precisam, e qual é a forma mais natural de expressar essas necessidades?

Começamos cada design de API com documentação de casos de uso — não definições de esquema ou listas de endpoints, mas descrições narrativas do que cada tipo de consumidor precisa de fazer. Uma app móvel a buscar um perfil de utilizador tem necessidades diferentes de um sistema de processamento batch a sincronizar dados de utilizadores. A API deve servir ambos bem sem forçar nenhum a contornar complexidade desnecessária.

Modelação de Recursos

Boa modelação de recursos é a base de uma API duradoura. Os recursos devem representar conceitos de negócio que são estáveis ao longo do tempo, não tabelas de base de dados ou fronteiras de serviços internos que podem mudar. Um recurso "cliente" deve expor a informação que os consumidores precisam sobre um cliente, independentemente de esses dados viverem numa base de dados ou em sete microserviços internamente.

Seguimos vários princípios para modelação de recursos: os recursos devem ser auto-descritivos (um consumidor deve conseguir compreender uma representação de recurso sem consultar documentação externa), as relações entre recursos devem ser navegáveis (use hyperlinks ou campos de relação explícitos, não convenções de ID implícitas), e a granularidade dos recursos deve corresponder aos padrões de acesso dos consumidores (não force consumidores a fazer cinco chamadas quando uma bastaria, mas não retorne megabytes de dados quando precisam de um único campo).

Estratégia de Versionamento

Toda API precisa de uma estratégia de versionamento, mesmo que espere nunca a usar. O debate entre versionamento baseado em URL (ex: /v2/users), versionamento por header, e content negotiation já foi extensamente discutido noutros locais. A nossa recomendação: use versionamento baseado em URL pela sua simplicidade e facilidade de debug, apenas com versões major. Alterações minor que são retrocompatíveis não requerem mudança de versão.

A questão mais importante é: o que constitui uma alteração incompatível? Mantemos uma definição clara: adicionar novos campos a objetos de resposta não é incompatível. Adicionar novos parâmetros de query opcionais não é incompatível. Remover campos, mudar tipos de campos, alterar formatos de resposta de erro, ou mudar o significado semântico de campos existentes — estas são alterações incompatíveis que requerem uma nova versão.

A Regra Aditiva

Dentro de uma versão major, seguimos a regra aditiva: pode adicionar novos endpoints, adicionar novos campos a respostas, adicionar novos parâmetros opcionais, e adicionar novos valores enum, mas não pode remover ou modificar nada de que consumidores existentes possam depender. Esta regra é simples de compreender, fácil de aplicar em revisão de código, e fornece uma garantia clara aos consumidores: a sua integração não vai quebrar enquanto permanecer na mesma versão major.

Tratamento de Erros como Funcionalidade

As respostas de erro são parte do contrato da sua API, e merecem a mesma atenção de design que as respostas de sucesso. Uma resposta de erro bem desenhada diz ao consumidor exatamente o que correu mal, porquê, e o que pode fazer. Uma mal desenhada retorna um 500 genérico sem informação acionável, forçando o consumidor a contactar o suporte.

Usamos uma estrutura de resposta de erro consistente em todos os endpoints: um código de erro legível por máquina (não o status HTTP, que é demasiado grosseiro para tratamento programático), uma mensagem legível por humanos adequada para logging, e quando aplicável, um apontador para o campo ou parâmetro específico que causou o erro e um link para documentação relevante. Esta estrutura permite que os consumidores construam tratamento de erros robusto sem adivinhar o significado de strings de erro crípticas.

Validação e Feedback Útil

Os erros de validação de input devem ser específicos e abrangentes. Em vez de retornar na primeira falha de validação, recolha todos os erros de validação e retorne-os em conjunto. Cada erro deve identificar o campo ofensivo, explicar a restrição violada, e idealmente sugerir o formato correto. Os consumidores não devem precisar de jogar whack-a-mole, corrigindo um erro de validação de cada vez através de submissões repetidas.

Paginação, Filtragem e Ordenação

Os endpoints de lista são onde o design de API mais frequentemente falha. A implementação inicial retorna todos os registos, o que funciona bem com 50 registos de teste e quebra catastroficamente com 50.000 registos de produção. Desenhe endpoints de lista com paginação desde o primeiro dia — retrofitar paginação num endpoint existente é uma alteração incompatível.

Preferimos paginação baseada em cursor sobre baseada em offset para a maioria dos casos de uso. A paginação por cursor é mais performante para datasets grandes, fornece resultados estáveis quando dados estão a ser modificados concorrentemente, e trata naturalmente o problema "onde é que eu estava?" para consumidores que processam dados em lotes. A troca é que os consumidores não podem saltar para uma página arbitrária, o que raramente é necessário para consumidores de API (ao contrário de paginação de UI).

Filtragem e ordenação devem seguir convenções consistentes em todos os endpoints de lista. Defina uma sintaxe clara para expressões de filtro, documente os campos e operadores disponíveis, e garanta que o mesmo nome de campo e sintaxe de filtro funciona da mesma forma em toda a sua API.

Documentação que se Mantém Atual

Documentação de API desatualizada é pior do que nenhuma documentação — ativamente engana os consumidores. Geramos documentação a partir da especificação da API (OpenAPI/Swagger) em vez de a manter separadamente, garantindo que a documentação reflete sempre a implementação atual. A especificação é a fonte de verdade, e é validada em CI para garantir que corresponde ao comportamento real da API.

Para além da documentação de referência, investimos em guias que explicam padrões de integração comuns, fornecem exemplos de código funcional em linguagens populares, e percorrem workflows end-to-end. Estes guias são versionados juntamente com a API e atualizados como parte do processo de release, não como pensamento posterior.

Rate Limiting e Uso Justo

O rate limiting protege a sua API de abuso e garante acesso justo para todos os consumidores. Mas o rate limiting também é parte do contrato da sua API e precisa do mesmo pensamento de design que qualquer outra funcionalidade. Comunique limites claramente na documentação e nos headers de resposta. Forneça diferentes tiers para diferentes classes de consumidores. Retorne respostas 429 informativas que digam ao consumidor exatamente quando pode tentar novamente. E nunca aplique rate limiting silenciosamente — os consumidores devem sempre saber quando foram throttled e porquê.

Pontos-Chave

  • Desenhe APIs da perspetiva do consumidor, não como um espelho do modelo de dados interno
  • Siga a regra aditiva dentro de versões major — adicione livremente, nunca remova ou modifique
  • Invista em respostas de erro que sejam específicas, acionáveis e consistentemente estruturadas
  • Implemente paginação baseada em cursor desde o primeiro dia — retrofitá-la depois é uma alteração incompatível
  • Gere documentação a partir da especificação da API para garantir que se mantém atual
  • Trate o rate limiting como uma funcionalidade com comunicação clara, não como um mecanismo de aplicação silencioso

Uma API que dura é aquela que respeita os seus consumidores. Cada decisão de design deve ser avaliada através da lente de: "isto ainda fará sentido para alguém a integrar com a nossa API daqui a um ano?" Essa disciplina — pensar para além do caso de uso imediato para a experiência do consumidor a longo prazo — é o que separa APIs que perduram daquelas que acumulam workarounds até serem substituídas.