DOMAIN: API Pública com Rate Limiting
Skill gerado a partir do pack templates-claude-code. Arquivo de origem: dominio/07-api-publica-rate-limiting.md. Use como baseline e adapte ao projeto antes de mudancas grandes.
Conteudo do template
CONTEXT
API pública é produto — não apenas infraestrutura. Desenvolvedores são seus usuários.
Rate limiting mal implementado quebra clientes legítimos; versionamento incorreto
quebra integrações sem aviso. A maioria dos times implementa rate limit global e
ignora estratégias por endpoint e por tier de cliente.
STACK ASSUMPTIONS
- Gateway: Kong, AWS API Gateway, Nginx, ou rate limiting na aplicação
- Rate Limit Storage: Redis (single source of truth para contadores)
- Auth: API Key (Bearer token no header) ou OAuth2 para terceiros
- Docs: OpenAPI 3.x (gerado a partir de código, não mantido manualmente)
- SDK: gerado automaticamente a partir do OpenAPI spec
CORE CONCEPTS
- Fixed Window: contador reiniciado a cada janela (ex: 100 req/minuto)
- Sliding Window: janela deslizante usando sorted set no Redis (mais justo, mais caro)
- Token Bucket: bucket de tokens reabastecido continuamente (permite burst dentro do limite)
- Leaky Bucket: processa requests em rate fixo independente de burst
- API Key Tiers: free (100/h), starter (1k/h), pro (10k/h), enterprise (unlimited + SLA)
- API Versioning: semver aplicado a contratos de API (breaking change = major version)
- Idempotency Key: header para operações mutantes (POST/PATCH) — safe para retry
ARCHITECTURE RULES
Rate Limiting Strategy
- Aplicar em camadas: global IP → API key → endpoint específico
- Headers obrigatórios em TODA response:
X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
- Status 429 com
Retry-After header (em segundos)
- Sliding window para endpoints críticos (auth, checkout)
- Token bucket para bulk endpoints (permite burst controlado)
- Whitelist para IPs internos e health checks
API Key Management
- Gerar:
prefix_base64urlsafe(32bytes) — ex: sk_live_aBcD1234...
- Armazenar apenas hash SHA-256 no banco — nunca o plaintext
- Exibir chave completa APENAS no momento da criação
- Escopos:
read, write, admin — chave pode ter múltiplos escopos
- Rotação: permitir criar nova key antes de revogar a antiga (zero downtime)
- Associar ao workspace/org, não ao usuário individual
Versionamento de URL
/v1/users → versão estável
/v2/users → nova versão com breaking changes
/users → NUNCA (sem versão = problema)
- Major version para breaking changes: remover campo, mudar tipo, alterar comportamento
- Minor changes (additive): novos campos opcionais, novos endpoints — sem nova versão
- Deprecation: header
Deprecation: true, Sunset: Sat, 31 Dec 2025 23:59:59 GMT
- Suporte a versão anterior por mínimo 12 meses após deprecação
OpenAPI Spec
- Spec gerada a partir de anotações no código (não mantida manualmente)
- Validação de request payload contra spec antes de chegar ao handler
- Spec versionada junto com o código
- Exemplos de request/response em cada operação
- Erros documentados com schema:
{ code, message, details }
Breaking Change Policy
- Nunca remover campo de response sem versão major
- Nunca mudar tipo de campo sem versão major
- Nunca alterar comportamento de endpoint existente sem versão major
- Adicionar campo novo a response: OK sem nova versão (clients devem ignorar unknown)
- Adicionar query param opcional: OK sem nova versão
ROUTING TABLE
| Trigger |
Action |
| Toda request com API key |
Verificar hash → checar escopo → aplicar rate limit do tier |
| Rate limit excedido |
429 + Retry-After + headers X-RateLimit-* |
| GET /v1/openapi.json |
Retornar spec OpenAPI atualizada |
| POST /v1/api-keys |
Criar key → retornar plaintext UMA VEZ → armazenar hash |
| DELETE /v1/api-keys/:id |
Revogar key → invalidar cache |
| GET /v1/api-keys/:id/usage |
Estatísticas de uso da key (calls/dia, endpoints) |
| POST /v1/resources (idempotent) |
Verificar Idempotency-Key header → deduplicar → processar |
| GET /v1/rate-limit-status |
Retornar status atual de rate limit da key autenticada |
| POST /admin/api-keys/:id/reset-limits |
Reset manual de contador (suporte tier enterprise) |
| GET /v1/health |
Sem auth, sem rate limit, retornar status e build info |
| GET /v1/changelog |
Listar breaking changes por versão |
| POST /webhooks/register |
Registrar endpoint para receber eventos via push |
CRITICAL RULES
- API key NUNCA armazenada em plaintext — somente hash SHA-256
- Rate limit em Redis, não em memória da aplicação (múltiplas instâncias)
- Headers
X-RateLimit-* presentes em 100% das responses
- Breaking change = nova versão major, sem exceção
- Versão antiga mantida por mínimo 12 meses após deprecação com aviso
- Validação do request body contra OpenAPI spec antes do handler
- Idempotency key obrigatória em POST mutantes de recursos (documentar no spec)
- Nunca retornar API key completa após a criação inicial
- Rate limit por API key + por IP (proteção contra roubo de key)
Retry-After header obrigatório em todas as responses 429
COMMON PITFALLS
❌ Rate limit em memória com múltiplos workers
// ERRADO: cada processo tem seu próprio contador — limite efetivo = N * limit
const counts = new Map(); // memória local
function checkRateLimit(key) {
const count = counts.get(key) || 0;
counts.set(key, count + 1);
return count < 100;
}
// CORRETO: Redis como contador compartilhado
async function checkRateLimit(key: string, limit: number, windowSeconds: number) {
const count = await redis.incr(`rl:${key}`);
if (count === 1) await redis.expire(`rl:${key}`, windowSeconds);
return count <= limit;
}
❌ Armazenar API key em plaintext
// ERRADO: leak do banco expõe todas as keys
await db.apiKeys.create({ key: rawKey, userId });
// CORRETO: armazenar hash, exibir apenas uma vez
const hash = crypto.createHash('sha256').update(rawKey).digest('hex');
await db.apiKeys.create({ keyHash: hash, prefix: rawKey.slice(0, 8), userId });
return { key: rawKey }; // único momento que o cliente vê a chave completa
❌ Remover campo de response sem versão
// ERRADO: v1 users retornava { id, name, email } — remover email quebra clients
// Solução: manter email em v1, remover apenas em v2
// CORRETO: deprecar antes de remover
res.set('Deprecation', 'true');
res.set('Sunset', 'Sat, 31 Dec 2025 23:59:59 GMT');
res.json({ id, name, email }); // mantém por mais 12 meses
QUALITY GATES
FORBIDDEN
- Armazenar API key em plaintext em qualquer storage
- Rate limiting com contadores em memória do processo
- Breaking changes sem bump de versão major
- Remover versão de API com < 12 meses de aviso
- Response sem headers
X-RateLimit-*
- Endpoint de produção sem versionamento na URL
- Receber dados de request sem validação contra schema
1---2name: tpl-dominio-api-publica-rate-limiting3description: Template do pack (dominio/07-api-publica-rate-limiting.md). Orienta o agente em regras de negocio e requisitos de produto alinhado a esse contexto.4---56# DOMAIN: API Pública com Rate Limiting78Skill gerado a partir do pack `templates-claude-code`. Arquivo de origem: `dominio/07-api-publica-rate-limiting.md`. Use como baseline e adapte ao projeto antes de mudancas grandes.910## Conteudo do template1112## CONTEXT13API pública é produto — não apenas infraestrutura. Desenvolvedores são seus usuários.14Rate limiting mal implementado quebra clientes legítimos; versionamento incorreto15quebra integrações sem aviso. A maioria dos times implementa rate limit global e16ignora estratégias por endpoint e por tier de cliente.1718## STACK ASSUMPTIONS19- Gateway: Kong, AWS API Gateway, Nginx, ou rate limiting na aplicação20- Rate Limit Storage: Redis (single source of truth para contadores)21- Auth: API Key (Bearer token no header) ou OAuth2 para terceiros22- Docs: OpenAPI 3.x (gerado a partir de código, não mantido manualmente)23- SDK: gerado automaticamente a partir do OpenAPI spec2425## CORE CONCEPTS26- **Fixed Window**: contador reiniciado a cada janela (ex: 100 req/minuto)27- **Sliding Window**: janela deslizante usando sorted set no Redis (mais justo, mais caro)28- **Token Bucket**: bucket de tokens reabastecido continuamente (permite burst dentro do limite)29- **Leaky Bucket**: processa requests em rate fixo independente de burst30- **API Key Tiers**: free (100/h), starter (1k/h), pro (10k/h), enterprise (unlimited + SLA)31- **API Versioning**: semver aplicado a contratos de API (breaking change = major version)32- **Idempotency Key**: header para operações mutantes (POST/PATCH) — safe para retry3334## ARCHITECTURE RULES3536### Rate Limiting Strategy37- Aplicar em camadas: global IP → API key → endpoint específico38- Headers obrigatórios em TODA response: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`39- Status 429 com `Retry-After` header (em segundos)40- Sliding window para endpoints críticos (auth, checkout)41- Token bucket para bulk endpoints (permite burst controlado)42- Whitelist para IPs internos e health checks4344### API Key Management45- Gerar: `prefix_base64urlsafe(32bytes)` — ex: `sk_live_aBcD1234...`46- Armazenar apenas hash SHA-256 no banco — nunca o plaintext47- Exibir chave completa APENAS no momento da criação48- Escopos: `read`, `write`, `admin` — chave pode ter múltiplos escopos49- Rotação: permitir criar nova key antes de revogar a antiga (zero downtime)50- Associar ao workspace/org, não ao usuário individual5152### Versionamento de URL53```54/v1/users → versão estável55/v2/users → nova versão com breaking changes56/users → NUNCA (sem versão = problema)57```58- Major version para breaking changes: remover campo, mudar tipo, alterar comportamento59- Minor changes (additive): novos campos opcionais, novos endpoints — sem nova versão60- Deprecation: header `Deprecation: true`, `Sunset: Sat, 31 Dec 2025 23:59:59 GMT`61- Suporte a versão anterior por mínimo 12 meses após deprecação6263### OpenAPI Spec64- Spec gerada a partir de anotações no código (não mantida manualmente)65- Validação de request payload contra spec antes de chegar ao handler66- Spec versionada junto com o código67- Exemplos de request/response em cada operação68- Erros documentados com schema: `{ code, message, details }`6970### Breaking Change Policy71- Nunca remover campo de response sem versão major72- Nunca mudar tipo de campo sem versão major73- Nunca alterar comportamento de endpoint existente sem versão major74- Adicionar campo novo a response: OK sem nova versão (clients devem ignorar unknown)75- Adicionar query param opcional: OK sem nova versão7677## ROUTING TABLE78| Trigger | Action |79|---------|--------|80| Toda request com API key | Verificar hash → checar escopo → aplicar rate limit do tier |81| Rate limit excedido | 429 + `Retry-After` + headers `X-RateLimit-*` |82| GET /v1/openapi.json | Retornar spec OpenAPI atualizada |83| POST /v1/api-keys | Criar key → retornar plaintext UMA VEZ → armazenar hash |84| DELETE /v1/api-keys/:id | Revogar key → invalidar cache |85| GET /v1/api-keys/:id/usage | Estatísticas de uso da key (calls/dia, endpoints) |86| POST /v1/resources (idempotent) | Verificar `Idempotency-Key` header → deduplicar → processar |87| GET /v1/rate-limit-status | Retornar status atual de rate limit da key autenticada |88| POST /admin/api-keys/:id/reset-limits | Reset manual de contador (suporte tier enterprise) |89| GET /v1/health | Sem auth, sem rate limit, retornar status e build info |90| GET /v1/changelog | Listar breaking changes por versão |91| POST /webhooks/register | Registrar endpoint para receber eventos via push |9293## CRITICAL RULES941. API key NUNCA armazenada em plaintext — somente hash SHA-256952. Rate limit em Redis, não em memória da aplicação (múltiplas instâncias)963. Headers `X-RateLimit-*` presentes em 100% das responses974. Breaking change = nova versão major, sem exceção985. Versão antiga mantida por mínimo 12 meses após deprecação com aviso996. Validação do request body contra OpenAPI spec antes do handler1007. Idempotency key obrigatória em POST mutantes de recursos (documentar no spec)1018. Nunca retornar API key completa após a criação inicial1029. Rate limit por API key + por IP (proteção contra roubo de key)10310. `Retry-After` header obrigatório em todas as responses 429104105## COMMON PITFALLS106107### ❌ Rate limit em memória com múltiplos workers108```javascript109// ERRADO: cada processo tem seu próprio contador — limite efetivo = N * limit110const counts = new Map(); // memória local111function checkRateLimit(key) {112 const count = counts.get(key) || 0;113 counts.set(key, count + 1);114 return count < 100;115}116117// CORRETO: Redis como contador compartilhado118async function checkRateLimit(key: string, limit: number, windowSeconds: number) {119 const count = await redis.incr(`rl:${key}`);120 if (count === 1) await redis.expire(`rl:${key}`, windowSeconds);121 return count <= limit;122}123```124125### ❌ Armazenar API key em plaintext126```javascript127// ERRADO: leak do banco expõe todas as keys128await db.apiKeys.create({ key: rawKey, userId });129130// CORRETO: armazenar hash, exibir apenas uma vez131const hash = crypto.createHash('sha256').update(rawKey).digest('hex');132await db.apiKeys.create({ keyHash: hash, prefix: rawKey.slice(0, 8), userId });133return { key: rawKey }; // único momento que o cliente vê a chave completa134```135136### ❌ Remover campo de response sem versão137```javascript138// ERRADO: v1 users retornava { id, name, email } — remover email quebra clients139// Solução: manter email em v1, remover apenas em v2140141// CORRETO: deprecar antes de remover142res.set('Deprecation', 'true');143res.set('Sunset', 'Sat, 31 Dec 2025 23:59:59 GMT');144res.json({ id, name, email }); // mantém por mais 12 meses145```146147## QUALITY GATES148- [ ] API keys armazenadas somente como hash SHA-256149- [ ] Rate limit em Redis (não memória local)150- [ ] Headers `X-RateLimit-*` em 100% das responses151- [ ] OpenAPI spec gerada automaticamente e válida152- [ ] Request body validado contra spec antes do handler153- [ ] Versão em cada URL (`/v1/`, `/v2/`)154- [ ] Deprecation headers em endpoints obsoletos155- [ ] `Retry-After` in 429 responses156- [ ] Idempotency key documentada e verificada em POST mutantes157- [ ] Health endpoint sem auth e sem rate limit158159## FORBIDDEN160- Armazenar API key em plaintext em qualquer storage161- Rate limiting com contadores em memória do processo162- Breaking changes sem bump de versão major163- Remover versão de API com < 12 meses de aviso164- Response sem headers `X-RateLimit-*`165- Endpoint de produção sem versionamento na URL166- Receber dados de request sem validação contra schema