[Nest.js] 커스텀 데코레이터로 코드 간결화 및 재사용성 향상하기

궁금하면 500원·2024년 8월 15일
0

Nest.js에서 커스텀 데코레이터를 만드는 방법을 포스팅 하였습니다.

데코레이터를 사용하면 메서드, 클래스, 파라미터 등에 메타데이터를 추가하여
다양한 기능을 쉽게 구현할 수 있습니다.

예를 들어, 특정 메서드의 매개변수를 커스텀하게 변환하거나,
특정 권한을 체크하는 등의 작업을 수행할 수 있습니다.

1. 커스텀 데코레이터 생성

Nest.js에서는 @nestjs/common 모듈에서 제공하는 createParamDecorator 함수를 이용하여 커스텀 데코레이터를 만들 수 있습니다.

요청 객체에서 특정 헤더 값을 추출하는 커스텀 데코레이터

1.커스텀 데코레이터 생성

// custom-header.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

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

이 데코레이터는 요청 객체에서 data로 전달된 헤더 값을 추출합니다.

2.컨트롤러에서 사용

// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { CustomHeader } from './custom-header.decorator';

@Controller('test')
export class AppController {
  @Get()
  getCustomHeader(@CustomHeader('authorization') authHeader: string): string {
    return `Authorization Header: ${authHeader}`;
  }
}

위의 코드에서 @CustomHeader('authorization')는 요청의 authorization 헤더 값을 authHeader 매개변수에 할당합니다.

2. 메서드/클래스 레벨의 데코레이터 생성

1.커스텀 메서드 데코레이터

커스텀 메서드 데코레이터는 특정 메서드에 추가적인 로직을 적용할 수 있습니다.

예를 들어, 메서드 실행 전/후에 특정 작업을 수행하도록 할 수 있습니다.

// logging.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const Logging = (message: string) => SetMetadata('loggingMessage', message);

2.데코레이터 적용

// app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { Logging } from './logging.decorator';

@Controller('test')
export class AppController {
  @Get()
  @Logging('This is a logging message')
  getHello(): string {
    return 'Hello World!';
  }
}

위의 @Logging 데코레이터는 SetMetadata를 사용하여
loggingMessage 메타데이터를 설정합니다.

이 메타데이터를 Guard, Interceptor, Pipe 등에서 활용하여 원하는 로직을
구현할 수 있습니다

3. 커스텀 데코레이터를 활용한 인증/권한 관리

Nest.js의 Guards와 함께 커스텀 데코레이터를 사용하면 권한 관리 로직을 효율적으로 구현할 수 있습니다.

권한 데코레이터 생성

1.Roles 데코레이터 생성

// roles.decorator.ts
import { SetMetadata } from '@nestjs/common';

export const Roles = (...roles: string[]) => SetMetadata('roles', roles);

2.RolesGuard 생성

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

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

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get<string[]>('roles', context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return roles.some((role) => user.roles?.includes(role));
  }
}

3.Roles 데코레이터 및 RolesGuard 적용

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

@Controller('test')
@UseGuards(RolesGuard)
export class AppController {
  @Get()
  @Roles('admin')
  getAdminContent(): string {
    return 'Admin Content';
  }
}

위의 코드는 @Roles 데코레이터를 사용하여 admin 권한이 있는 사용자만
접근할 수 있도록 설정합니다.

결론

스텀 데코레이터를 만드는 것은 매우 간단하며, 다양한 기능을 구현하는 데 매우 유용합니다.

데코레이터와 Guard, Interceptor, Pipe 등의
기능을 함께 사용하면 복잡한 비즈니스 로직도 손쉽게 구현할 수 있다는것을 배웠습니다.

profile
꾸준히, 의미있는 사이드 프로젝트 경험과 문제해결 과정을 기록하기 위한 공간입니다.

0개의 댓글