Saltar al contenido principal

Middleware, Testing, Documentación y Seguridad Avanzada

13. Regla sobre Middleware

Regla Principal

Regla: El Middleware (@Injectable que implementa NestMiddleware) debe usarse principalmente para lógica transversal que necesita ejecutarse antes de que la petición llegue al sistema de routing de NestJS (Guards, Pipes, Interceptors).

  1. Los casos de uso típicos y permitidos para Middleware incluyen: logging crudo de peticiones, manipulación de headers (ej. CORS, Helmet), integración con librerías de terceros que operan a nivel de request/response de Express/Fastify, o autenticación muy básica (aunque Passport/Guards suelen ser preferibles).
  2. El Middleware debe implementarse como una clase @Injectable que implementa NestMiddleware y su método use(req, res, next).
  3. La configuración y aplicación del Middleware debe hacerse en el método configure del módulo correspondiente (implementando NestModule). Se debe especificar las rutas a las que aplica (forRoutes).
  4. Está prohibido usar Middleware para lógica de autorización (usar Guards), validación/transformación de datos de parámetros/body (usar Pipes), o manipulación de la respuesta saliente (usar Interceptors).
  5. Middleware reutilizable debe ubicarse en src/common/middleware o en src/middleware si es específico de la aplicación.

Contexto y Justificación

El Middleware opera a un nivel más bajo que los Guards, Pipes e Interceptors de NestJS, interactuando directamente con los objetos request y response del framework subyacente (Express/Fastify). Su uso debe ser limitado a tareas que no encajan bien en los otros componentes del ciclo de vida de la petición de NestJS. Abusar del Middleware para tareas que pueden resolverse con Guards, Pipes o Interceptors viola la separación de responsabilidades y desaprovecha las características de NestJS.

Ejemplos y Contraejemplos

  • Correcto (Logger Middleware Simple):
    // --- src/common/middleware/logger.middleware.ts ---
    import { Injectable, NestMiddleware, Logger } from '@nestjs/common';
    import { Request, Response, NextFunction } from 'express';

    @Injectable()
    export class LoggerMiddleware implements NestMiddleware {
    private readonly logger = new Logger('HTTP'); // Contexto para el Logger

    use(request: Request, response: Response, next: NextFunction): void {
    const { method, originalUrl, ip } = request;
    const userAgent = request.get('user-agent') || '';

    // Loggea antes de que la respuesta se envíe
    response.on('finish', () => {
    const { statusCode } = response;
    const contentLength = response.get('content-length');
    this.logger.log(
    `${method} ${originalUrl} ${statusCode} ${contentLength} - ${userAgent} ${ip}`
    );
    });

    next(); // Llama a next() para pasar al siguiente middleware o handler
    }
    }

    // --- src/app.module.ts ---
    import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
    import { LoggerMiddleware } from './common/middleware/logger.middleware';
    // ... otros imports

    @Module({ /* ... imports, controllers, providers ... */ })
    export class AppModule implements NestModule {
    configure(consumer: MiddlewareConsumer) {
    consumer
    .apply(LoggerMiddleware) // Aplica el middleware
    .forRoutes('*'); // Aplica a todas las rutas
    // O .forRoutes({ path: 'items', method: RequestMethod.GET }); para rutas específicas
    }
    }
  • Incorrecto: Usar Middleware para verificar un token JWT (usar JwtAuthGuard). Usar Middleware para parsear un parámetro id a número (usar ParseIntPipe). Usar Middleware para envolver la respuesta en un objeto { data: ... } (usar TransformInterceptor).

Cuándo Aplicar

Para configuración de CORS, Helmet, logging básico de request/response, o integración con librerías específicas de Express/Fastify.

Cuándo Evitar o Flexibilizar

Evitar siempre que la funcionalidad pueda implementarse usando Guards, Pipes o Interceptors, ya que estos están mejor integrados con el ecosistema NestJS (DI, metadatos, ExecutionContext).

14. Regla sobre Testing (Unit, Integration, E2E)

Regla Principal

Regla: El código generado debe ser testeable y, cuando sea aplicable o solicitado, la IA debe generar pruebas unitarias, de integración y/o E2E utilizando el framework @nestjs/testing y Jest.

  1. Pruebas Unitarias (.spec.ts):
    • Deben enfocarse en una única clase (servicio, controlador, pipe, guard) aislándola de sus dependencias.
    • Las dependencias (otros servicios, repositorios, ConfigService) deben ser mockeadas usando jest.fn(), jest.spyOn() o creando mocks manuales/automáticos.
    • Se debe usar Test.createTestingModule para instanciar la clase bajo prueba, proveyendo los mocks para sus dependencias.
    • Los servicios deben ser testeados exhaustivamente, cubriendo la lógica de negocio y el manejo de errores.
    • Los controladores deben testearse verificando que llaman a los métodos correctos del servicio con los argumentos correctos, sin reimplementar la lógica del servicio.
  2. Pruebas de Integración (.integration.spec.ts o similar):
    • Deben verificar la interacción entre varias clases dentro de un módulo o entre módulos, usando menos mocks que las pruebas unitarias.
    • Pueden requerir configurar un TestingModule más completo, posiblemente conectando a una base de datos de prueba (ej. en Docker).
    • Son útiles para probar el flujo completo de una funcionalidad a nivel de módulo.
  3. Pruebas E2E (.e2e-spec.ts):
    • Deben probar la aplicación completa a través de sus endpoints HTTP, como lo haría un cliente.
    • Se debe usar el setup proporcionado por NestJS CLI que utiliza supertest.
    • Deben instanciar la aplicación completa (Test.createTestingModule().compile()) y realizar peticiones HTTP reales a la app en ejecución (en modo test).
    • Deben cubrir los flujos de usuario más críticos.
  4. Ubicación: Las pruebas unitarias (.spec.ts) deben ubicarse junto al archivo que prueban. Las pruebas E2E (.e2e-spec.ts) deben estar en el directorio test/.

Contexto y Justificación

El testing es crucial para asegurar la calidad, prevenir regresiones y facilitar refactorizaciones seguras. NestJS proporciona herramientas excelentes (@nestjs/testing) que facilitan la creación de diferentes tipos de pruebas. Las pruebas unitarias verifican componentes aislados, las de integración aseguran la colaboración entre componentes y las E2E validan el sistema completo desde la perspectiva del cliente.

Ejemplos y Contraejemplos

  • Correcto (Prueba Unitaria de Servicio):
    // --- src/modules/items/services/items.service.ts ---
    import { Injectable, Inject, NotFoundException } from '@nestjs/common';
    import { IItemRepository, ITEM_REPOSITORY_TOKEN } from '../interfaces/item.repository.interface';
    import { Item } from '../entities/item.entity';
    import { CreateItemDto } from '../dtos/create-item.dto';

    @Injectable()
    export class ItemsService {
    constructor(
    @Inject(ITEM_REPOSITORY_TOKEN) private readonly itemRepository: IItemRepository,
    ) {}

    async findById(id: string): Promise<Item> {
    const item = await this.itemRepository.findById(id);
    if (!item) {
    throw new NotFoundException(`Item con ID ${id} no encontrado`);
    }
    return item;
    }

    async create(dto: CreateItemDto): Promise<Item> {
    // ... validación de negocio ...
    return this.itemRepository.create(dto);
    }
    }

    // --- src/modules/items/services/items.service.spec.ts ---
    import { Test, TestingModule } from '@nestjs/testing';
    import { ItemsService } from './items.service';
    import { IItemRepository, ITEM_REPOSITORY_TOKEN } from '../interfaces/item.repository.interface';
    import { NotFoundException } from '@nestjs/common';
    import { Item } from '../entities/item.entity';
    import { CreateItemDto } from '../dtos/create-item.dto';

    // Mock del repositorio
    const mockItemRepository: Partial<IItemRepository> = {
    findById: jest.fn(),
    create: jest.fn(),
    };

    describe('ItemsService', () => {
    let service: ItemsService;

    beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
    providers: [
    ItemsService,
    {
    provide: ITEM_REPOSITORY_TOKEN,
    useValue: mockItemRepository, // Usa el mock
    },
    ],
    }).compile();

    service = module.get<ItemsService>(ItemsService);
    jest.clearAllMocks(); // Limpia mocks entre tests
    });

    it('should be defined', () => {
    expect(service).toBeDefined();
    });

    describe('findById', () => {
    it('debe retornar un item si existe', async () => {
    const mockId = 'some-uuid';
    const expectedItem: Item = { id: mockId, name: 'Test Item', price: 100 };
    (mockItemRepository.findById as jest.Mock).mockResolvedValue(expectedItem);

    const result = await service.findById(mockId);

    expect(result).toEqual(expectedItem);
    expect(mockItemRepository.findById).toHaveBeenCalledWith(mockId);
    expect(mockItemRepository.findById).toHaveBeenCalledTimes(1);
    });

    it('debe lanzar NotFoundException si el item no existe', async () => {
    const mockId = 'non-existent-uuid';
    (mockItemRepository.findById as jest.Mock).mockResolvedValue(null);

    await expect(service.findById(mockId)).rejects.toThrow(NotFoundException);
    expect(mockItemRepository.findById).toHaveBeenCalledWith(mockId);
    });
    });

    describe('create', () => {
    it('debe llamar al repositorio con el DTO y retornar el item creado', async () => {
    const dto: CreateItemDto = { name: 'New Item', price: 200 };
    const createdItem: Item = { id: 'new-uuid', ...dto };
    (mockItemRepository.create as jest.Mock).mockResolvedValue(createdItem);

    const result = await service.create(dto);

    expect(result).toEqual(createdItem);
    expect(mockItemRepository.create).toHaveBeenCalledWith(dto);
    });
    });
    });
  • Incorrecto: Pruebas unitarias que dependen de una base de datos real. Pruebas E2E mockeando servicios internos. No testear casos de error o edge cases. Pruebas de controlador que reimplementan lógica ya probada en el servicio.

Cuándo Aplicar

Siempre. Escribir código testeable y generar pruebas (especialmente unitarias para servicios) es fundamental para la calidad del software.

Cuándo Evitar o Flexibilizar

La cantidad y tipo de pruebas pueden variar según la criticidad del módulo y los recursos disponibles. Sin embargo, la lógica de negocio core siempre debería tener pruebas unitarias. Las pruebas E2E son más costosas de mantener y pueden enfocarse en los flujos críticos.

15. Regla sobre Logging

Regla Principal

Regla: Se debe implementar un sistema de logging estructurado y configurable en toda la aplicación NestJS.

  1. Usar Logger de @nestjs/common: Utilizar la clase Logger incorporada o extenderla para necesidades básicas. Para aplicaciones más complejas o que requieran alto rendimiento/formato JSON, se recomienda usar librerías como pino a través de nestjs-pino.
  2. Inyección de Dependencias: Inyectar Logger (o LoggerService) en clases (servicios, controladores, etc.) en lugar de instanciarlo directamente. Se puede declarar como miembro estático en casos donde la inyección no es fácil.
  3. Contexto: Proveer un contexto (this.logger = new Logger('UsersService')) al crear instancias del logger para identificar fácilmente el origen del log.
  4. Niveles de Log: Utilizar los niveles de log apropiados (log, error, warn, debug, verbose) según la severidad y naturaleza del mensaje.
  5. Configuración: Configurar los niveles de log habilitados (ej. debug en desarrollo, log/warn/error en producción) preferentemente a través de variables de entorno (LOG_LEVEL) y ConfigService.
  6. Información Útil: Incluir información relevante en los logs, como IDs de correlación, identificadores de usuario (si aplica y es seguro), y detalles del error (sin exponer información sensible).
  7. Prohibido console.log: Está prohibido usar console.log, console.error, etc., directamente en el código de la aplicación (excepto quizás en main.ts durante el bootstrap inicial). Usar siempre el Logger inyectado.

Contexto y Justificación

Un buen sistema de logging es esencial para la observabilidad, depuración y monitoreo de la aplicación en cualquier entorno. Usar el sistema de logging de NestJS (o librerías integradas) asegura consistencia, permite configurar niveles y formatos, y facilita la integración con herramientas de recolección y análisis de logs. Evitar console.log permite un control centralizado sobre qué se loggea y dónde.

Ejemplos y Contraejemplos

  • Correcto (Uso de Logger incorporado):
    import { Injectable, Logger, Scope, Inject } from '@nestjs/common';
    import { REQUEST } from '@nestjs/core'; // Para obtener request-scoped data
    import { Request } from 'express';

    @Injectable()
    export class MyService {
    // Inyecta el logger estándar
    private readonly logger = new Logger(MyService.name);

    doSomething(userId: string, data: any) {
    this.logger.log(`Iniciando operación para usuario ${userId}...`);
    try {
    // ... lógica de negocio ...
    if (data.value < 0) {
    this.logger.warn(`Valor negativo detectado: ${data.value}`, { userId, data });
    }
    this.logger.debug('Operación intermedia completada', { userId }); // Log de depuración
    // ... más lógica ...
    this.logger.log(`Operación completada exitosamente para usuario ${userId}.`);
    } catch (error) {
    this.logger.error(`Falló la operación para usuario ${userId}: ${error.message}`, error.stack, { userId, data });
    throw error; // Relanza el error
    }
    }
    }

    // --- Logger Request-Scoped (Opcional, para incluir info de request) ---
    @Injectable({ scope: Scope.REQUEST })
    export class RequestScopedLogger {
    private readonly logger = new Logger(RequestScopedLogger.name);
    private correlationId: string;

    constructor(@Inject(REQUEST) private readonly request: Request) {
    // Asume que un middleware/interceptor añadió 'correlationId' al request
    this.correlationId = (request as any).correlationId || 'N/A';
    }

    log(message: string, context?: string) {
    this.logger.log(`[CorrID: ${this.correlationId}] ${message}`, context);
    }
    error(message: string, trace?: string, context?: string) {
    this.logger.error(`[CorrID: ${this.correlationId}] ${message}`, trace, context);
    }
    // ... otros niveles ...
    }

    // --- Configuración básica en main.ts ---
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { Logger } from '@nestjs/common';

    async function bootstrap() {
    const app = await NestFactory.create(AppModule, {
    // Habilita niveles de log basados en una variable de entorno (ej)
    // logger: process.env.NODE_ENV === 'production' ? ['log', 'warn', 'error'] : ['log', 'error', 'warn', 'debug', 'verbose'],
    // O usar un logger personalizado:
    // logger: new MyCustomLogger()
    });
    // ...
    await app.listen(3000);
    Logger.log(`Aplicación corriendo en ${await app.getUrl()}`, 'Bootstrap');
    }
    bootstrap();
  • Incorrecto: Usar console.log('Usuario creado:' + userId) por toda la aplicación. No incluir contexto en los logs. Loggear información sensible (contraseñas, tokens completos). No tener niveles de log configurables.

Cuándo Aplicar

Siempre. El logging debe estar presente desde el inicio del desarrollo.

Cuándo Evitar o Flexibilizar

Nunca se debe omitir el logging. La complejidad de la configuración (logger simple vs. nestjs-pino) puede variar según el proyecto, pero el principio de usar un logger estructurado y configurable es constante.

16. Regla sobre Documentación (Swagger/OpenAPI)

Regla Principal

Regla: Toda API REST desarrollada con NestJS debe ser documentada utilizando el estándar OpenAPI (anteriormente Swagger) a través del módulo @nestjs/swagger.

  1. Setup Global: Configurar SwaggerModule en main.ts para generar el documento OpenAPI y exponer la UI de Swagger (ej. en /api-docs).
  2. Decoradores de Controlador: Usar @ApiTags en cada controlador para agrupar endpoints por recurso.
  3. Decoradores de Método: Usar @ApiOperation({ summary: '...', description: '...' }) para describir cada endpoint. Usar @ApiResponse({ status: 200, description: '...', type: MyDto }) para cada posible respuesta (éxito y error), especificando el DTO de respuesta si aplica.
  4. Decoradores de DTO: Usar @ApiProperty({ description: '...', example: '...', required: true/false }) en cada propiedad de los DTOs (de entrada y salida) para documentar los schemas.
  5. Autenticación: Documentar los esquemas de seguridad (ej. JWT, OAuth2) usando DocumentBuilder.addBearerAuth() y @ApiBearerAuth() en los endpoints protegidos.
  6. La documentación generada debe ser clara, completa y consistente con la implementación de la API.

Contexto y Justificación

La documentación de API es esencial para que los consumidores (frontend, otras APIs, desarrolladores) entiendan cómo interactuar con ella. @nestjs/swagger se integra perfectamente con los decoradores y DTOs de NestJS para generar automáticamente documentación OpenAPI interactiva y precisa, reduciendo el esfuerzo manual y asegurando que la documentación se mantenga sincronizada con el código.

Ejemplos y Contraejemplos

  • Correcto (Setup y Decoradores):
    // --- src/main.ts ---
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
    import { ValidationPipe } from '@nestjs/common';

    async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    app.useGlobalPipes(new ValidationPipe({ whitelist: true, forbidNonWhitelisted: true }));

    const config = new DocumentBuilder()
    .setTitle('Mi API de Items')
    .setDescription('Documentación de la API para gestionar ítems')
    .setVersion('1.0')
    .addTag('items', 'Operaciones sobre ítems') // Añade tag global
    .addTag('auth', 'Autenticación')
    .addBearerAuth() // Configura seguridad Bearer (JWT)
    .build();
    const document = SwaggerModule.createDocument(app, config);
    SwaggerModule.setup('api-docs', app, document); // Expone en /api-docs

    await app.listen(3000);
    }
    bootstrap();

    // --- src/modules/items/dtos/item.dto.ts ---
    import { ApiProperty } from '@nestjs/swagger';
    import { Exclude } from 'class-transformer';

    export class ItemDto {
    @ApiProperty({ description: 'ID único del ítem (UUID)', example: 'a1b2c3d4-...' })
    id: string;

    @ApiProperty({ description: 'Nombre del ítem', example: 'Laptop XYZ' })
    name: string;

    @ApiProperty({ description: 'Precio del ítem', example: 1299.99, type: 'number' })
    price: number;

    @ApiProperty({ description: 'Fecha de creación', example: '2023-10-27T10:00:00.000Z' })
    createdAt: Date;

    @Exclude() // No se muestra en la API (gracias a ClassSerializerInterceptor)
    internalCode: string;
    }

    // --- src/modules/items/dtos/create-item.dto.ts ---
    import { ApiProperty } from '@nestjs/swagger';
    import { IsString, IsNotEmpty, IsNumber, Min } from 'class-validator';

    export class CreateItemDto {
    @ApiProperty({ description: 'Nombre del nuevo ítem', example: 'Teclado Mecánico', maxLength: 100 })
    @IsString()
    @IsNotEmpty()
    name: string;

    @ApiProperty({ description: 'Precio del nuevo ítem', example: 89.50, minimum: 0 })
    @IsNumber()
    @Min(0)
    price: number;
    }

    // --- src/modules/items/controllers/items.controller.ts ---
    import {
    Controller, Get, Post, Body, Param, HttpCode, UseGuards, ParseUUIDPipe
    } from '@nestjs/common';
    import { ItemsService } from '../services/items.service';
    import { CreateItemDto } from '../dtos/create-item.dto';
    import { ItemDto } from '../dtos/item.dto';
    import {
    ApiTags, ApiOperation, ApiResponse, ApiParam, ApiBody, ApiBearerAuth
    } from '@nestjs/swagger';
    import { JwtAuthGuard } from '@app/common/guards/jwt-auth.guard'; // Asume guard JWT

    @ApiTags('items') // Agrupa bajo la tag 'items'
    @ApiBearerAuth() // Indica que estos endpoints requieren autenticación Bearer
    @UseGuards(JwtAuthGuard)
    @Controller('items')
    export class ItemsController {
    constructor(private readonly itemsService: ItemsService) {}

    @Post()
    @HttpCode(201)
    @ApiOperation({ summary: 'Crea un nuevo ítem', description: 'Registra un nuevo ítem en el sistema.' })
    @ApiBody({ type: CreateItemDto })
    @ApiResponse({ status: 201, description: 'Ítem creado exitosamente.', type: ItemDto })
    @ApiResponse({ status: 400, description: 'Datos de entrada inválidos.' })
    @ApiResponse({ status: 401, description: 'No autorizado.' })
    create(@Body() createItemDto: CreateItemDto): Promise<ItemDto> {
    return this.itemsService.create(createItemDto);
    }

    @Get(':id')
    @ApiOperation({ summary: 'Obtiene un ítem por su ID' })
    @ApiParam({ name: 'id', description: 'UUID del ítem a buscar', type: 'string', format: 'uuid' })
    @ApiResponse({ status: 200, description: 'Ítem encontrado.', type: ItemDto })
    @ApiResponse({ status: 404, description: 'Ítem no encontrado.' })
    @ApiResponse({ status: 401, description: 'No autorizado.' })
    findOne(@Param('id', ParseUUIDPipe) id: string): Promise<ItemDto> {
    return this.itemsService.findById(id);
    }
    }
  • Incorrecto: No configurar SwaggerModule. No usar decoradores @Api... en controladores, métodos o DTOs. Documentación incompleta o inconsistente con el código. No documentar respuestas de error comunes (400, 401, 403, 404, 500).

Cuándo Aplicar

Siempre, para todas las APIs REST públicas o internas.

Cuándo Evitar o Flexibilizar

Nunca se debe omitir la documentación OpenAPI para una API NestJS. El nivel de detalle en las descripciones puede variar, pero la estructura (tags, operations, responses, schemas) debe estar completa.

17. Regla sobre Seguridad Avanzada

Regla Principal

Regla: Además de la validación de entradas (Norma 6) y autorización (Norma 9), la aplicación NestJS debe implementar medidas de seguridad adicionales para protegerse contra vulnerabilidades comunes.

  1. Protección de Headers (Helmet): Utilizar helmet (middleware de Express) para establecer cabeceras HTTP seguras (X-Frame-Options, Strict-Transport-Security, etc.). Aplicarlo globalmente en main.ts.
  2. Protección CSRF (Cross-Site Request Forgery): Si la aplicación usa autenticación basada en cookies/sesiones (menos común en APIs REST puras que usan tokens), implementar protección CSRF usando csurf (middleware) o mecanismos equivalentes.
  3. Rate Limiting: Implementar limitación de peticiones (Rate Limiting) para prevenir ataques de fuerza bruta o denegación de servicio. Usar express-rate-limit (middleware) o el módulo @nestjs/throttler. Aplicarlo globalmente o en endpoints sensibles.
  4. Seguridad de Dependencias: Mantener las dependencias del proyecto actualizadas regularmente. Utilizar npm audit o yarn audit (o herramientas como Snyk) para identificar y corregir vulnerabilidades conocidas en paquetes de terceros.
  5. Manejo Seguro de Secretos: Asegurar que los secretos (claves API, contraseñas de BD, secretos JWT) se gestionen de forma segura (usando @nestjs/config, variables de entorno, vaults) y nunca se expongan en el código fuente ni en logs.
  6. HTTPS: Configurar la aplicación para que se ejecute exclusivamente sobre HTTPS en producción.

Contexto y Justificación

La seguridad es una preocupación transversal. Más allá de la validación y autorización básicas, existen otros vectores de ataque comunes contra aplicaciones web. Implementar medidas como Helmet, Rate Limiting y mantener las dependencias actualizadas añade capas de defensa importantes para proteger la aplicación y sus usuarios.

Ejemplos y Contraejemplos

  • Correcto (Aplicación de Helmet y Throttler):
    // --- src/main.ts ---
    import { NestFactory } from '@nestjs/core';
    import { AppModule } from './app.module';
    import helmet from 'helmet';
    import { ThrottlerGuard } from '@nestjs/throttler';
    import { APP_GUARD } from '@nestjs/core';

    // ... otros imports, setup swagger, validation pipe ...

    async function bootstrap() {
    const app = await NestFactory.create(AppModule);
    // ... validation pipe, swagger ...

    // Aplica Helmet globalmente
    app.use(helmet());

    // Configura CORS si es necesario (antes o después de helmet)
    app.enableCors(/* opciones de configuración */);

    // Throttler se configura en AppModule y se aplica globalmente vía APP_GUARD

    await app.listen(3000);
    }
    bootstrap();

    // --- src/app.module.ts ---
    import { Module } from '@nestjs/common';
    import { ConfigModule } from '@nestjs/config';
    import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';
    import { APP_GUARD } from '@nestjs/core';
    // ... otros imports

    @Module({
    imports: [
    ConfigModule.forRoot({ isGlobal: true, /* ... */ }),
    ThrottlerModule.forRoot([{
    ttl: 60000, // Tiempo de vida en milisegundos (1 minuto)
    limit: 10, // Límite de peticiones por ttl por IP
    }]),
    // ... otros módulos
    ],
    providers: [
    // Aplica ThrottlerGuard globalmente a todas las rutas
    {
    provide: APP_GUARD,
    useClass: ThrottlerGuard,
    },
    // ... otros providers
    ],
    })
    export class AppModule {}

    // --- Para Rate Limiting específico (Opcional) ---
    import { Controller, Get, UseGuards } from '@nestjs/common';
    import { Throttle } from '@nestjs/throttler';

    @Controller('auth')
    export class AuthController {
    @Throttle({ default: { limit: 3, ttl: 60000 } }) // Sobrescribe el global para este endpoint
    @Post('login')
    login(/* ... */) {
    // ...
    }
    }
  • Incorrecto: No usar Helmet. No implementar Rate Limiting en endpoints públicos o de autenticación. No revisar ni actualizar dependencias regularmente. Exponer secretos en el código o logs. Ejecutar en HTTP en producción.

Cuándo Aplicar

Siempre. Estas medidas de seguridad básicas (Helmet, Rate Limiting, gestión de dependencias, HTTPS) son obligatorias para cualquier aplicación en producción.

Cuándo Evitar o Flexibilizar

Nunca se deben omitir estas prácticas de seguridad fundamentales. La configuración específica (ej. límites de Rate Limiting) puede ajustarse según las necesidades, pero la implementación debe existir.