Nestjs - Custom route decorators

haaaalin·2023년 5월 16일
0

Nest.js는 HTTP route handlers와 함께 사용할 수 있는 유용한 매개변수 decorator를 제공한다.

Param decorators

또한 이와 비슷한 사용자 지정 데코레이터를 만들 수 있다.

Node.js를 사용하던 세계에서는 아래와 같이 객체에 request 속성을 수동적으로 붙이는 게 일반적이었다.

const user = req.user;

명백하고, 가독성 좋은 코드를 작성하기 위해 아래와 같이 @User() 데코레이터를 만들고 모든 컨트롤러에서 재사용할 수 있다.

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

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

위에서 만든 @User 데코레이터는 아래처럼 사용할 수 있다.

@Get()
async findOne(@User() user: UserEntity) {
  console.log(user);
}

passing data

만약, decorator가 동작이 일부 조건에 따라 달라지는 경우, data 매개 변수를 사용하여 decorator의 factory function에 전달하면 된다.

예시로 request 객체에서 키로 속성을 추출하는 custom decorator를 보여주고 있다.

아래는 User 엔티티를 보여주고 있다.

{
  "id": 101,
  "firstName": "Alan",
  "lastName": "Turing",
  "email": "alan@email.com",
  "roles": ["admin"]
}

User 속성 이름을 key로 사용하고 해당 값이 존재하는 경우 값을 반환하는 decorator

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

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

    return data ? user?.[data] : user;
  },
);

아래는 위에서 만든 decorator를 사용한 코드이다.

@Get()
async findOne(@User('firstName') firstName: string) {
  console.log(`Hello ${firstName}`);
}

pipe 작업

Nest는 custom param decorator 들도 @Body(), @Param(), @Query() 등과 같이 처리한다.

즉, pipe가 custom annotated parameter(앞서 봤던 user) 같은 매개변수에도 실행됨을 의미한다.

@Get()
async findOne(
  @User(new ValidationPipe({ validateCustomDecorators: true }))
  user: UserEntity,
) {
  console.log(user);
}

따라서 validateCustomDecorators 를 true로 설정해야 한다.

decorator 합치기

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

export function Auth(...roles: Role[]) {
  return applyDecorators(
    SetMetadata('roles', roles),
    UseGuards(AuthGuard, RolesGuard),
    ApiBearerAuth(),
    ApiUnauthorizedResponse({ description: 'Unauthorized' }),
  );
}

위처럼 많은 데코레이터를 단일 데코레이터로 결합할 수 있다

profile
한 걸음 한 걸음 쌓아가자😎

0개의 댓글