TypeScript por baixo dos panos: Rate limiting e throttling sem dor

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Como evitar que sua API caia sob uma enxurrada de requisições

\n\n

Imagine: você lançou um serviço incrível, escreveu o backend em TypeScript, e de repente — bum! — um usuário "bonzinho" executa um script que bombardeia seu endpoint com milhares de requisições por segundo. O servidor cai, o banco de dados trava, e os usuários honestos veem o erro 502. Familiar?

\n\n

No mundo do desenvolvimento web, rate limiting (limitação de frequência de requisições) e throttling (estrangulamento) não são apenas palavras da moda, mas sim uma tábua de salvação para sua API. Hoje vamos explorar como implementar esses mecanismos em TypeScript sem complicação. Vamos lá!

\n\n

Rate limiting vs Throttling: qual a diferença?

\n\n

Antes de escrever código, vamos definir claramente os conceitos. Muitos os confundem, mas a diferença é fundamental.

\n\n
    \n
  • Rate limiting — é um limite rígido: "No máximo 100 requisições por minuto de um único IP". Ultrapassou? Recebe um 429 Too Many Requests e bloqueio até o final da janela. Funciona no nível do API gateway.
  • \n
  • Throttling — é uma regulação suave: "Você pode fazer requisições, mas não mais do que uma por segundo". As demais requisições são enfileiradas ou ignoradas, mas o usuário não é bloqueado.
  • \n
\n\n

Uma analogia simples: rate limiting é a catraca do metrô (passou o cartão, passou; não passou, espera), enquanto throttling é o semáforo no cruzamento (os carros andam, mas com intervalo).

\n\n

Quando isso é necessário? Cenários reais

\n\n

Você pode dizer: "Meu site é pequeno, para que preciso disso?" Veja porquê:

\n\n
    \n
  • Proteção contra DDoS e brute force — invasores não conseguirão testar senhas ou derrubar o servidor.
  • \n
  • Economia de recursos — APIs pagas (como OpenAI) cobram por cada chamada. Limitar os clientes salva seu orçamento.
  • \n
  • Distribuição justa de carga — um usuário "barulhento" não sufoca todos os outros.
  • \n
  • Cumprimento de SLA — se você promete uptime de 99,9%, não tem como evitar limitações.
  • \n
\n\n

Escrevendo rate limiting em TypeScript: início simples

\n\n

Vamos começar com um exemplo básico — um rate limiter in-memory baseado em janela fixa (Fixed Window). Ele armazena contadores de requisições diretamente na memória da aplicação.

\n\n
// rateLimiter.ts\nimport { Request, Response, NextFunction } from 'express';\n\ninterface RateLimitEntry {\n    count: number;\n    resetTime: number;\n}\n\nclass InMemoryRateLimiter {\n    private store: Map<string, RateLimitEntry> = new Map();\n    private windowMs: number;\n    private maxRequests: number;\n\n    constructor(windowMs: number, maxRequests: number) {\n        this.windowMs = windowMs;\n        this.maxRequests = maxRequests;\n    }\n\n    public middleware() {\n        return (req: Request, res: Response, next: NextFunction): void => {\n            const key = req.ip || 'unknown';\n            const now = Date.now();\n            let entry = this.store.get(key);\n\n            if (!entry || now > entry.resetTime) {\n                // Nova janela\n                entry = { count: 0, resetTime: now + this.windowMs };\n                this.store.set(key, entry);\n            }\n\n            entry.count++;\n\n            if (entry.count > this.maxRequests) {\n                res.status(429).json({\n                    error: 'Too Many Requests',\n                    retryAfter: Math.ceil((entry.resetTime - now) / 1000)\n                });\n                return;\n            }\n\n            // Passa informações do limite nos cabeçalhos\n            res.setHeader('X-RateLimit-Limit', this.maxRequests);\n            res.setHeader('X-RateLimit-Remaining', this.maxRequests - entry.count);\n            res.setHeader('X-RateLimit-Reset', Math.ceil(entry.resetTime / 1000));\n\n            next();\n        };\n    }\n\n    // Limpeza de registros antigos (para evitar vazamento de memória)\n    public cleanup(): void {\                

Blogs

Book Recommendations