Decoradores personalizados

Intermedio
Nest
Nest
Actualizado: 15/06/2025

Decoradores personalizados

Los decoradores personalizados en NestJS permiten crear funcionalidades reutilizables que encapsulan lógica específica de tu aplicación. Mientras que los decoradores integrados como @Body() o @Param() cubren casos comunes, los decoradores personalizados te permiten extraer y procesar datos de manera específica según las necesidades de tu proyecto.

NestJS proporciona la función createParamDecorator() que facilita la creación de estos decoradores. Esta función recibe dos parámetros: los datos opcionales que se pasan al decorador y el contexto de ejecución que contiene información sobre la petición actual.

Creación básica de un decorador personalizado

Para crear un decorador personalizado, utilizamos la función createParamDecorator() junto con el contexto de ejecución:

import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const User = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user;
  },
);

Este decorador @User() extrae automáticamente el objeto usuario de la petición, simplificando el acceso a esta información en los controladores:

@Controller('profile')
export class ProfileController {
  @Get()
  getProfile(@User() user: any) {
    return user;
  }
}

Decoradores con parámetros específicos

Los decoradores personalizados pueden recibir parámetros para extraer propiedades específicas del objeto. El parámetro data contiene el valor pasado al decorador:

export const User = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;
    
    return data ? user?.[data] : user;
  },
);

Ahora puedes usar el decorador para extraer propiedades específicas del usuario:

@Controller('profile')
export class ProfileController {
  @Get('name')
  getUserName(@User('name') userName: string) {
    return { name: userName };
  }
  
  @Get('email')
  getUserEmail(@User('email') email: string) {
    return { email };
  }
}

Decoradores para validación y transformación

Los decoradores personalizados también pueden realizar validaciones y transformaciones de datos antes de pasarlos al método del controlador:

import { BadRequestException } from '@nestjs/common';

export const ValidatedUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const user = request.user;
    
    if (!user) {
      throw new BadRequestException('Usuario no autenticado');
    }
    
    if (!user.isActive) {
      throw new BadRequestException('Usuario inactivo');
    }
    
    return {
      id: user.id,
      email: user.email,
      role: user.role,
      lastLogin: new Date(user.lastLogin)
    };
  },
);

Decoradores para extracción de headers

Un caso común es crear decoradores para extraer información específica de los headers de la petición:

export const ApiKey = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    const apiKey = request.headers['x-api-key'];
    
    if (!apiKey) {
      throw new BadRequestException('API Key requerida');
    }
    
    return apiKey;
  },
);

export const UserAgent = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.headers['user-agent'];
  },
);

Estos decoradores simplifican el acceso a información específica de los headers:

@Controller('api')
export class ApiController {
  @Get('data')
  getData(
    @ApiKey() apiKey: string,
    @UserAgent() userAgent: string
  ) {
    return {
      message: 'Datos obtenidos correctamente',
      apiKey,
      userAgent
    };
  }
}

Combinación con pipes

Los decoradores personalizados funcionan perfectamente con pipes para realizar validaciones y transformaciones adicionales:

export const UserId = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return request.user?.id;
  },
);
import { ParseIntPipe } from '@nestjs/common';

@Controller('users')
export class UsersController {
  @Get('posts')
  getUserPosts(@UserId(ParseIntPipe) userId: number) {
    return this.postsService.findByUserId(userId);
  }
}

Decoradores para contextos específicos

También puedes crear decoradores que funcionen en contextos específicos como WebSockets o microservicios:

export const SocketUser = createParamDecorator(
  (data: unknown, ctx: ExecutionContext) => {
    const client = ctx.switchToWs().getClient();
    return client.user;
  },
);

export const RpcData = createParamDecorator(
  (data: string, ctx: ExecutionContext) => {
    const rpcContext = ctx.switchToRpc();
    const payload = rpcContext.getData();
    
    return data ? payload[data] : payload;
  },
);

Los decoradores personalizados mejoran la legibilidad del código y promueven la reutilización de lógica común. Al encapsular la extracción y validación de datos en decoradores específicos, reduces la duplicación de código y mantienes los métodos de los controladores enfocados en su lógica principal.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en Nest

Documentación oficial de Nest
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Nest es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Nest

Explora más contenido relacionado con Nest y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Comprender qué son los decoradores personalizados en NestJS y su utilidad.
  • Aprender a crear decoradores personalizados básicos usando createParamDecorator().
  • Saber cómo pasar parámetros a decoradores para extraer datos específicos.
  • Implementar validaciones y transformaciones dentro de decoradores personalizados.
  • Aplicar decoradores personalizados en diferentes contextos, incluyendo HTTP, WebSockets y microservicios.