Nest.js는 HTTP route handlers와 함께 사용할 수 있는 유용한 매개변수 decorator를 제공한다.
또한 이와 비슷한 사용자 지정 데코레이터를 만들 수 있다.
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);
}
만약, 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}`);
}
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로 설정해야 한다.
import { applyDecorators } from '@nestjs/common';
export function Auth(...roles: Role[]) {
return applyDecorators(
SetMetadata('roles', roles),
UseGuards(AuthGuard, RolesGuard),
ApiBearerAuth(),
ApiUnauthorizedResponse({ description: 'Unauthorized' }),
);
}
위처럼 많은 데코레이터를 단일 데코레이터로 결합할 수 있다