Guards, Interceptores y Pipes
Aplica autenticación, validación, registro y transformación de respuestas con los guards, interceptores y pipes de NestJS 11.
Receta
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
import { Controller, Get, Param, UseGuards, UseInterceptors, UsePipes, ValidationPipe } from "@nestjs/common";
import { AuthGuard } from "./auth.guard.js";
import { LoggingInterceptor } from "./logging.interceptor.js";
@Controller("users")
@UseGuards(AuthGuard)
@UseInterceptors(LoggingInterceptor)
export class UsersController {
@Get(":id")
@UsePipes(ValidationPipe)
findOne(@Param("id") id: string) {
return { id };
}
}Orden de ejecución: Middleware -> Guards -> Interceptores (antes) -> Pipes -> Manejador -> Interceptores (después) -> Filtros de Excepción
Ejemplo de trabajo
// auth.guard.ts
import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from "@nestjs/common";
@Injectable()
export class AuthGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const req = context.switchToHttp().getRequest();
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) throw new UnauthorizedException();
req.userId = "user-42";
return true;
}
}
// logging.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from "@nestjs/common";
import { Observable, tap } from "rxjs";
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
const start = Date.now();
const req = context.switchToHttp().getRequest();
return next.handle().pipe(
tap(() => console.log(`${req.method} ${req.url} ${Date.now() - start}ms`))
);
}
}
// roles.guard.ts
import { SetMetadata, Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
export const ROLES_KEY = "roles";
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get<string[]>(ROLES_KEY, context.getHandler());
if (!roles) return true;
const req = context.switchToHttp().getRequest();
return roles.includes(req.userRole);
}
}Lo que esto demuestra:
- El Guard devuelve
booleano lanza una excepción para permitir/denegar el acceso - El Interceptor envuelve al manejador con
pipede RxJS para lógica antes/después SetMetadata+Reflectorpara comprobaciones de roles declarativas- Los Guards e interceptores son inyectables (la DI funciona)
Análisis profundo
Cómo funciona
| Componente | Se ejecuta cuando | Propósito | Devuelve |
|---|---|---|---|
| Pipe | Antes del manejador | Transforma/valida la entrada | Valor transformado |
| Guard | Antes del manejador | Autenticación/autorización | true o lanza una excepción |
| Interceptor | Alrededor del manejador | Registro, caché, mapeo | Flujo observable |
| Filter | En caso de excepción | Formato de respuesta de error | Respuesta HTTP |
Registro global
// main.ts
app.useGlobalGuards(new AuthGuard());
app.useGlobalInterceptors(new LoggingInterceptor());
app.useGlobalPipes(new ValidationPipe({ whitelist: true }));Pipes incorporados
| Pipe | Propósito |
|---|---|
ValidationPipe | Validación de DTO con class-validator |
ParseIntPipe | Parámetro de cadena a entero |
ParseUUIDPipe | Valida el formato UUID |
DefaultValuePipe | Valor predeterminado para parámetros opcionales |
Errores comunes
- Guard después del interceptor en mente, no en código - los guards se ejecutan antes que los interceptores. Solución: pon la autenticación en guards, no en interceptores.
- ValidationPipe sin decoradores DTO - la validación no hace nada. Solución: añade decoradores
class-validatora las clases DTO. - Errores del interceptor no capturados por el filtro - los errores de RxJS necesitan
catchError. Solución: manéjalos en el interceptor o deja que el filtro de excepciones los capture. - Guard global bloquea la comprobación de salud - las sondas de K8s fallan. Solución: decorador
@Public()con un guard que omita las rutas marcadas. - Guard con ámbito de solicitud en un singleton - desajuste de ámbito. Solución: coincide los ámbitos o usa Reflector para metadatos.
- Registro de PII en el interceptor - registra solo el método/ruta/duración, no los cuerpos.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Middleware de Express | NestJS en Express, autenticación simple | Quieres guards declarativos por ruta |
| Hooks de Fastify | Adaptador NestJS en Fastify | Necesitas la DX del decorador de Nest |
| Middleware en NestJS | Acceso directo a solicitud/respuesta (cors) | Autenticación (los guards son mejores) |
| Comprobaciones manuales en el controlador | Prototipo rápido | Autenticación en producción |
Preguntas frecuentes
¿Guard vs middleware para autenticación?
Los Guards tienen acceso al contexto de ejecución (manejador, metadatos de clase) y se integran con Reflector. El Middleware es de nivel inferior. Prefiere los guards para la autenticación.
¿Pueden los interceptores modificar la respuesta?
Sí. Usa el operador map() para transformar el valor de retorno. O usa tap() solo para efectos secundarios.
¿Cómo omito la autenticación para rutas específicas?
Crea un decorador de metadatos @Public() y compruébalo en el AuthGuard con Reflector.
¿Cuál es la diferencia entre pipe y guard?
Los Pipes transforman/validan los datos que entran al manejador. Los Guards deciden si el manejador debe ejecutarse o no.
¿Cómo añado la temporización de solicitudes globalmente?
LoggingInterceptor global con tap() midiendo el tiempo transcurrido. O usa un interceptor de OpenTelemetry.
¿Funcionan los pipes en gateways de WebSocket?
Sí. NestJS también soporta guards, pipes e interceptores en contextos de WebSocket y RPC.
¿Cómo se compara ValidationPipe con Fastify JSON Schema?
ValidationPipe usa decoradores class-validator. Fastify usa JSON Schema. Sintaxis diferente, mismo objetivo.
¿Puedo usar múltiples guards en una ruta?
Sí. @UseGuards(AuthGuard, RolesGuard) ejecuta todos los guards en orden. Todos deben devolver true.
Relacionado
- Conceptos básicos de NestJS - estructura de módulos
- Inyección de dependencias - guards inyectables
- Middleware de seguridad - equivalente en Express
- Patrón Middleware - concepto subyacente
- Mejores prácticas de NestJS - lista de verificación de la sección
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activa), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.