Rate Limiting

Protecao contra abuso com limites globais e por rota.

Visao geral

Rate limiting protege sua API contra abuso, brute force e DDoS. O PlazerCLI configura limites globais com possibilidade de override por rota.

Configuracao padrao

VariavelPadraoDescricao
RATE_LIMIT_MAX100Maximo de requests por janela
RATE_LIMIT_WINDOW_MS60000Janela de tempo em ms (1 minuto)

NestJS — @nestjs/throttler

Usa o modulo oficial @nestjs/throttler com 3 presets de throttle:

@Module({
  imports: [
    ThrottlerModule.forRootAsync({
      useFactory: (configService: ConfigService) => ({
        throttlers: [
          { name: 'short',  ttl: 10_000,   limit: 10  },  // burst
          { name: 'medium', ttl: 60_000,   limit: 100 },  // geral
          { name: 'long',   ttl: 600_000,  limit: 200 },  // sustentado
        ],
      }),
    }),
  ],
  providers: [
    { provide: APP_GUARD, useClass: ThrottlerGuard },
  ],
})
export class ThrottleModule {}

O guard e registrado globalmente. Para pular throttle em uma rota:

import { SkipThrottle } from '@nestjs/throttler';

@SkipThrottle()
@Get('health')
health() { ... }

// Override de limite por rota:
@Throttle({ default: { limit: 5, ttl: 60000 } })
@Post('upload')
upload() { ... }

Express — express-rate-limit

Dois limiters pre-configurados sao gerados:

// Limiter padrao (100 req / 60s)
export const defaultLimiter = rateLimit({
  windowMs: Number(process.env.RATE_LIMIT_WINDOW_MS) || 60_000,
  max: Number(process.env.RATE_LIMIT_MAX) || 100,
  standardHeaders: 'draft-7',
  legacyHeaders: false,
});

// Limiter estrito para auth (10 req / 15min)
export const strictLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 10,
});

// Factory para criar limiters customizados
export function createLimiter(overrides) {
  return rateLimit({ windowMs: 60_000, max: 100, ...overrides });
}

// Uso:
app.use('/api', defaultLimiter);
app.use('/api/auth', strictLimiter);

Fastify — @fastify/rate-limit

Plugin Fastify registrado globalmente:

async function rateLimiterPlugin(app: FastifyInstance) {
  await app.register(rateLimit, {
    max: Number(process.env.RATE_LIMIT_MAX) || 100,
    timeWindow: Number(process.env.RATE_LIMIT_WINDOW_MS) || 60_000,
  });
}

// Override por rota:
app.get('/heavy', {
  config: { rateLimit: { max: 5, timeWindow: '1 minute' } }
}, handler);

// Desabilitar por rota:
app.get('/health', {
  config: { rateLimit: false }
}, handler);

Resposta de erro (429)

// HTTP 429 Too Many Requests
{
  "error": "Too Many Requests",
  "message": "Too many requests, please try again later.",
  "retryAfter": "30s"
}

// Headers retornados:
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 1708000000
Retry-After: 30