본문 바로가기

개발자 강화/백엔드

🌟[공부] NestJS의 Custom Decorators란?

NestJS의 Custom Decorators

반복적인 로직을 재사용 가능하게 만들고, 코드의 가독성을 높이기 위해 사용함

NestJS에서 제공하는 기본 데코레이터(@Body(), @Query(), @Param() 등) 외에 사용자가 직접 커스텀 데코레이터 정의

 

Custom Decorator의 필요성

1. 반복되는 코드 제거: 컨트롤러에서 동일한 로직을 적용할 때 유용

2. 코드 가독성 향상: req.user.id 같은 접근 방식을 단순화 가능

3. Middleware 또는 Guard와 조합 가능: 사용자 인증, 권한 체크 등에 활용

 

Custom Decorator 사용법

1. 메소드 매개변수용 데코레이터

컨트롤러에서 매개변수 값 추출 및 변환을 쉽게 하기 위한 데코레이터

 

@GetUser() 데코레이터를 만들어서, JWT 인증 유저를 가져오는 예제

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

// 사용자 요청에서 user 객체를 추출하는 커스텀 데코레이터
export const GetUser = createParamDecorator(
  (data: string | undefined, ctx: ExecutionContext) => {
    const request = ctx.switchToHttp().getRequest();
    return data ? request.user?.[data] : request.user;
  },
);
import { Controller, Get } from '@nestjs/common';
import { GetUser } from './get-user.decorator';

@Controller('users')
export class UserController {
  @Get('profile')
  getProfile(@GetUser() user: any) {
    return user; // request.user 반환
  }

  @Get('email')
  getUserEmail(@GetUser('email') email: string) {
    return { email }; // request.user.email 반환
  }
}

 

GET /users/profile 요청 시 -> request.user 전체 반환

GET /users/email 요청 시 -> request.user.email 값 반환

 

2. 클래스/메소드용 데코레이터

특정 권한(Authorization)이나 로그 기능을 자동으로 적용할 때 유용함

@SetMetadata()를 사용해 메타데이터를 추가하고, Guard에서 활용 가능

 

@Roles() 데코레이터(역할 기반 권한 부여) 예제

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

// 역할(Role) 기반 권한 제어를 위한 커스텀 데코레이터
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

'roles'라는 키를 사용해 메타 데이터를 추가함

 

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!requiredRoles) return true; // 역할 정보가 없으면 그냥 통과

    const request = context.switchToHttp().getRequest();
    const user = request.user; // JWT 인증된 사용자

    return user && requiredRoles.includes(user.role);
  }
}

@Roles() 데코레이터를 활용해 Roles Guard 구현

@Roles() 데코레이터에 @SetMetadata로 추가한 'roles' 키 값을 확인해서 역할을 확인함

 

RolesGuard에서 역할을 체크해 접근을 제어할 수 있음

import { Controller, Get, UseGuards } from '@nestjs/common';
import { Roles } from './roles.decorator';
import { RolesGuard } from './roles.guard';

@Controller('admin')
@UseGuards(RolesGuard) // Guard에서 역할을 확인
export class AdminController {
  @Get()
  @Roles('admin') // "admin" 역할을 가진 사용자만 접근 가능
  getAdminData() {
    return { message: 'Admin data' };
  }
}

Controller에 적용한 부분

@Roles('admin')이 있는 컨트롤러 메소드에서는 RolesGuard가 역할을 확인하고

"admin" 역할이 있는 경우만 요청을 허용함


출처

[1] NestJS 공식 Docs. Custom Route Decorators https://docs.nestjs.com/custom-decorators

[2] Toss Tech 블로그. NestJS 환경에 맞는 Custom Decorator 만들기. https://toss.tech/article/nestjs-custom-decorator

[3] GPT에게 커스텀 데코레이터에 대해 묻다