workspace-v1/shared/libs/rate-limiting
Adrian Flores Cortes 967ab360bb Initial commit: Workspace v1 with 3-layer architecture
Structure:
- control-plane/: Registries, SIMCO directives, CI/CD templates
- projects/: Gamilit, ERP-Suite, Trading-Platform, Betting-Analytics
- shared/: Libs catalog, knowledge-base

Key features:
- Centralized port, domain, database, and service registries
- 23 SIMCO directives + 6 fundamental principles
- NEXUS agent profiles with delegation rules
- Validation scripts for workspace integrity
- Dockerfiles for all services
- Path aliases for quick reference

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-23 00:35:19 -06:00
..
_reference Initial commit: Workspace v1 with 3-layer architecture 2025-12-23 00:35:19 -06:00
IMPLEMENTATION.md Initial commit: Workspace v1 with 3-layer architecture 2025-12-23 00:35:19 -06:00
README.md Initial commit: Workspace v1 with 3-layer architecture 2025-12-23 00:35:19 -06:00

Limitación de Tasa (Rate Limiting)

Versión: 1.0.0 Origen: projects/gamilit Estado: Producción Última actualización: 2025-12-08


Descripción

Sistema de limitación de tasa para proteger APIs contra abuso:

  • Rate limiting por IP/usuario
  • Configuración por endpoint
  • Headers HTTP estándar
  • Respuestas 429 con Retry-After

Características

Característica Descripción
Por IP Limita requests por dirección IP
Por Usuario Limita requests por usuario autenticado
Por Endpoint Configuración individual por ruta
Global Límite base para toda la aplicación
Headers Estándar X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After

Stack Tecnológico

backend:
  framework: NestJS
  library: "@nestjs/throttler"
  storage: "Memory (default) | Redis (producción)"

Dependencias NPM

{
  "@nestjs/throttler": "^5.x"
}

Para producción con Redis:

{
  "@nestjs/throttler-storage-redis": "^0.x",
  "redis": "^4.x"
}

Configuración Básica

En módulo principal

import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
import { APP_GUARD } from '@nestjs/core';

@Module({
  imports: [
    ThrottlerModule.forRoot([{
      ttl: 60000,  // 60 segundos
      limit: 100,  // 100 requests por TTL
    }]),
  ],
  providers: [
    {
      provide: APP_GUARD,
      useClass: ThrottlerGuard,
    },
  ],
})
export class AppModule {}

Configuración por ambiente

ThrottlerModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ([{
    ttl: config.get('THROTTLE_TTL', 60000),
    limit: config.get('THROTTLE_LIMIT', 100),
  }]),
})

Uso por Endpoint

Sobrescribir límites

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

@Controller('auth')
export class AuthController {

  // Más estricto: 5 intentos por minuto
  @Throttle({ default: { limit: 5, ttl: 60000 } })
  @Post('login')
  login() {}

  // Omitir rate limiting
  @SkipThrottle()
  @Get('public')
  publicEndpoint() {}
}

En controlador completo

@Controller('api')
@Throttle({ default: { limit: 50, ttl: 60000 } })
export class ApiController {
  // Todos los endpoints heredan el límite
}

Múltiples Límites

ThrottlerModule.forRoot([
  {
    name: 'short',
    ttl: 1000,    // 1 segundo
    limit: 3,     // 3 requests por segundo
  },
  {
    name: 'medium',
    ttl: 10000,   // 10 segundos
    limit: 20,    // 20 requests por 10 segundos
  },
  {
    name: 'long',
    ttl: 60000,   // 1 minuto
    limit: 100,   // 100 requests por minuto
  },
])

Usar en endpoint:

@Throttle({
  short: { limit: 1, ttl: 1000 },
  long: { limit: 10, ttl: 60000 },
})
@Post('expensive-operation')
expensiveOperation() {}

Rate Limiting por Usuario

Custom ThrottlerGuard

import { Injectable, ExecutionContext } from '@nestjs/common';
import { ThrottlerGuard } from '@nestjs/throttler';

@Injectable()
export class CustomThrottlerGuard extends ThrottlerGuard {
  protected async getTracker(req: Record<string, any>): Promise<string> {
    // Si hay usuario autenticado, usar su ID
    if (req.user?.id) {
      return req.user.id;
    }
    // Fallback a IP
    return req.ip;
  }
}

Registrar:

providers: [
  {
    provide: APP_GUARD,
    useClass: CustomThrottlerGuard,
  },
],

Almacenamiento Redis (Producción)

import { ThrottlerStorageRedisService } from '@nestjs/throttler-storage-redis';
import Redis from 'ioredis';

ThrottlerModule.forRootAsync({
  imports: [ConfigModule],
  inject: [ConfigService],
  useFactory: (config: ConfigService) => ({
    throttlers: [{
      ttl: config.get('THROTTLE_TTL', 60000),
      limit: config.get('THROTTLE_LIMIT', 100),
    }],
    storage: new ThrottlerStorageRedisService(new Redis({
      host: config.get('REDIS_HOST', 'localhost'),
      port: config.get('REDIS_PORT', 6379),
    })),
  }),
})

Headers de Respuesta

El módulo agrega automáticamente:

X-RateLimit-Limit: 100         # Límite máximo
X-RateLimit-Remaining: 95      # Requests restantes
X-RateLimit-Reset: 1234567890  # Timestamp de reset

En respuesta 429:

Retry-After: 60                # Segundos hasta poder reintentar

Excepciones Personalizadas

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

// En el guard personalizado
protected throwThrottlingException(): void {
  throw new ThrottlerException(
    'Demasiadas solicitudes. Por favor, espere un momento.',
  );
}

Variables de Entorno

# Configuración básica
THROTTLE_TTL=60000        # Ventana de tiempo en ms
THROTTLE_LIMIT=100        # Requests por ventana

# Redis (producción)
REDIS_HOST=localhost
REDIS_PORT=6379

Casos de Uso Comunes

1. Login (anti brute-force)

@Throttle({ default: { limit: 5, ttl: 300000 } }) // 5 por 5 minutos
@Post('login')
login() {}

2. Registro (anti spam)

@Throttle({ default: { limit: 3, ttl: 3600000 } }) // 3 por hora
@Post('register')
register() {}

3. API pública

@Throttle({ default: { limit: 1000, ttl: 3600000 } }) // 1000 por hora
@Get('public-data')
getData() {}

4. Endpoints costosos

@Throttle({ default: { limit: 10, ttl: 60000 } }) // 10 por minuto
@Post('generate-report')
generateReport() {}

Métricas y Logging

@Injectable()
export class ThrottlerLoggerGuard extends ThrottlerGuard {
  protected async handleRequest(
    context: ExecutionContext,
    limit: number,
    ttl: number,
  ): Promise<boolean> {
    const req = context.switchToHttp().getRequest();
    const tracker = await this.getTracker(req);

    const result = await super.handleRequest(context, limit, ttl);

    if (!result) {
      this.logger.warn(`Rate limit exceeded for: ${tracker}`);
    }

    return result;
  }
}

Adaptaciones Necesarias

  1. Límites: Ajustar según tráfico esperado
  2. Storage: Memory para desarrollo, Redis para producción
  3. Tracker: IP vs Usuario según necesidad
  4. Mensajes: Personalizar respuestas 429

Referencias


Mantenido por: Sistema NEXUS Proyecto origen: Gamilit Platform