# 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

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

---

## Dependencias NPM

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

Para producción con Redis:
```json
{
  "@nestjs/throttler-storage-redis": "^0.x",
  "redis": "^4.x"
}
```

---

## Configuración Básica

### En módulo principal

```typescript
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

```typescript
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

```typescript
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

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

---

## Múltiples Límites

```typescript
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:

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

---

## Rate Limiting por Usuario

### Custom ThrottlerGuard

```typescript
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:

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

---

## Almacenamiento Redis (Producción)

```typescript
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

```typescript
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

```env
# 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)

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

### 2. Registro (anti spam)

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

### 3. API pública

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

### 4. Endpoints costosos

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

---

## Métricas y Logging

```typescript
@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

- [NestJS Throttler](https://docs.nestjs.com/security/rate-limiting)
- [RFC 6585](https://tools.ietf.org/html/rfc6585#section-4) (429 Too Many Requests)

---

**Mantenido por:** Sistema NEXUS
**Proyecto origen:** Gamilit Platform
