Playbook de APIs maduras

Boas práticas para criar APIs fáceis de usar

Se tem uma coisa que todo dev já viveu é tentar usar uma API mal pensada.

  • Documentação confusa.
  • Endpoints com nomes estranhos.
  • Erros que não dizem nada.
  • Paginação improvisada.

Você começa achando que vai levar 2 horas… e quando vê, já perdeu uma tarde inteira brigando com um 400 Bad Request.

A boa notícia? Quase sempre isso não é problema de tecnologia. É problema de padrão.

Neste conteúdo, vou trazer os principais aprendizados de um playbook de APIs moderno. A ideia é simples:

  • 👉 reduzir fricção para quem desenvolve
  • 👉 criar consistência entre produtos
  • 👉 aumentar a maturidade técnica
  • 👉 facilitar integrações

Sem firula. Bora.

Por que padronizar APIs não é burocracia

Existe um mito perigoso no mundo da engenharia:

“Cada time faz do seu jeito porque é mais rápido.”

Spoiler: não é.

Quando cada API segue um padrão diferente, você cria:

  • mais carga cognitiva
  • mais tempo de onboarding
  • mais bugs de integração
  • mais suporte
  • mais retrabalho

Padronização não engessa. Ela remove decisões desnecessárias.

O time deixa de discutir coisas básicas e passa a focar no que realmente gera valor.

Comece pela maturidade da sua API

Um dos modelos mais conhecidos para avaliar APIs é o Richardson Maturity Model.

A meta saudável para a maioria das empresas? Ficar entre o nível 2 e o 3.

Na prática, isso significa:

  • usar corretamente os verbos HTTP
  • ter endpoints claros
  • evitar ambiguidade
  • nomear recursos de forma consistente
  • considerar hypermedia quando fizer sentido

Não precisa transformar tudo em uma tese acadêmica.

Mas também não dá pra ter rota tipo:

/getUserDataNowPlease

Tenha respeito pelo seu “eu do futuro”.

Rotas boas são rotas previsíveis

Uma regra simples resolve metade dos problemas:

👉 Use substantivos no plural para coleções.

Exemplo:

GET /contacts
GET /contacts/{id}

Sem invenção.

Outro ponto importante: se existir mais de um identificador, deixe isso explícito.

Exemplo:

/contacts/email:nome@email.com

Quem consome a API agradece.

“Search” não diz nada.

Filtrar pelo quê?

Prefira algo explícito:

/contacts?filter[country]=Brazil

Quer múltiplos valores?

filter[state]=SP,SC

Simples. Legível. Escalável.

Operadores lógicos

Padronize também:

  • gt → greater than
  • gte → greater or equal
  • lt → lower than
  • lte → lower or equal

Exemplo clássico:

filter[createdAt][gte]=2024-01-01

Zero mistério.

Paginação: não invente moda

A abordagem tradicional resolve 90% dos casos:

?page[number]=2&page[size]=10

Mas tem um detalhe que muita API ignora:

👉 devolva links de navegação.

Exemplo:

  • first
  • last
  • next
  • prev

Isso facilita absurdamente a vida do frontend.

Se quiser ir além, adicione metadados:

  • total de itens
  • página atual
  • tamanho

Não é obrigatório. Mas é elegante.

Ordenação deve ser óbvia

Use:

?sort=createdAt

Ordem crescente por padrão.

Quer inverter?

?sort=-createdAt

Evite order. É ambíguo.

Outra dica pouco falada:

👉 permita múltiplas ordenações.

Igual ao SQL:

?sort=createdAt,name

Versionamento: escolha o caminho mais fácil de entender

Existem várias estratégias, mas uma segue vencendo pela clareza:

👉 versão na URL.

/v1/contacts

Motivos:

  • visual
  • fácil de debugar
  • difícil de ignorar
  • simples para quem integra

Headers são elegantes… até alguém esquecer de mandar.

Estrutura de requisição e resposta

Um padrão extremamente saudável:

Requests e responses com data na raiz

{
  "data": { }
}

Isso traz consistência.

Metadados opcionais

{
  "data": {},
  "meta": {},
  "links": {}
}

Organizado. Previsível. Profissional.

Erros que ajudam de verdade

Pare de devolver só:

400 Bad Request

Explique o problema.

Uma boa estrutura inclui:

  • tipo do erro
  • título
  • detalhe
  • origem

Exemplo:

{
  "errors": [{
    "type": "validation_error",
    "title": "Invalid attribute",
    "detail": "Name cannot be empty",
    "source": {
      "pointer": "/data/name"
    }
  }]
}

Isso reduz suporte. Reduz frustração. Reduz tempo de debug.

Todo mundo ganha.

Documentação não é opcional

Se a API é boa mas ninguém entende como usar…

Ela é ruim.

Hoje, o padrão de mercado é o OpenAPI.

E aqui vai um conselho valioso:

👉 leve a documentação para perto do código.

Documentação manual sempre fica desatualizada.

Automatize via CI.

Criou endpoint? Atualizou doc no PR.

Sem exceção.

API Gateway: tire complexidade dos serviços

Um gateway bem configurado deveria cuidar de:

  • Autenticação
  • Rate limit
  • Segurança
  • Roteamento

Isso evita que cada produto reinvente a roda.

Além disso, permite:

  • bloquear acessos diretos
  • centralizar políticas
  • melhorar observabilidade

Arquitetura madura não depende da boa vontade dos times.

Ela cria trilhos.

Rate limit não é só técnico. É produto.

Muita gente define limite só com base na infra.

Erro.

Rate limit também ajuda a:

  • proteger o sistema
  • controlar abuso
  • diferenciar planos
  • incentivar upgrades

Não existe número mágico.

Mas existe regra obrigatória:

👉 API pública sem rate limit é um acidente esperando para acontecer.

Observabilidade não é luxo

Se você não mede…

Você está no escuro.

Alguns SLIs recomendados:

Disponibilidade

  • 99% para APIs comuns
  • 99.9% para críticas

Latência

  • P95 < 500ms
  • P99 < 1s

Taxa de erro

  • 500 < 1%
  • 400 < 5%

Curiosidade importante:

Muitos erros 400 geralmente indicam documentação ruim.

Testes mínimos para APIs maduras

Se existe um atalho perigoso em engenharia, ele se chama “depois a gente testa”.

Para manter uma API saudável, alguns testes não são negociáveis:

Essenciais:

  • Testes de unidade → garantem que a lógica funciona em isolamento.
  • Testes de integração → validam se tudo conversa direito: banco, filas, serviços externos.
  • Testes de segurança → evitam que sua API vire porta aberta para problemas sérios.

Fortemente recomendados:

  • Testes de carga → mostram até onde sua API aguenta antes de começar a pedir arrego.
  • Testes de contrato → protegem integrações contra mudanças inesperadas.

Ferramentas como o K6 facilitam bastante a simulação de tráfego real e ajudam a encontrar gargalos antes dos usuários encontrarem por você.

No fim das contas, é simples:

API sem teste não é velocidade. É aposta.

E produção não deveria ser cassino.

Um ponto cultural (e talvez o mais importante)

Um playbook não é uma lei universal.

É um acordo.

Não existe “polícia da API”.

Mas existe algo melhor:

👉 engenharia madura.

O objetivo não é atingir perfeição amanhã.

É criar uma direção clara.

APIs antigas vão evoluir. Novas já nascem melhores.

E aos poucos…

A experiência de integração vira um diferencial competitivo.

Para levar com você

Se precisar lembrar de apenas uma coisa, que seja esta:

Uma boa API não é a que funciona. É a que qualquer dev consegue usar sem sofrimento.

Padronize. Documente. Automatize. Observe. Teste.

E, principalmente:

Evite fazer alguém perder uma sexta-feira debugando sua API.