네스트에서의 데코레이터
네스트에서는 데코레이터라는 기능을 사용할 수 있다.
데코레이터는 다른 언어들에서는 흔하게 사용되는 개념이지만, 자바스크립트 진영에서는 아직은 낯선 편이다.
데코레이터의 정의를 간단히 살펴보면 아래와 같다.
ES2016에서 데코레이터란 함수를 반환하고, 인자로 대상(target), 이름, 프로퍼티 설명자(property descriptor)를 받을 수 있다. @를 앞에 붙여, 데코레이트하고 싶은 것 위에 위치시킨다. 데코레이터는 클래스, 메서드, 또는 프로퍼티로 정의될 수 있다.
네스트 Param 데코레이터
네스트는 http 라우터 핸들러와 사용할 수 있는 파라미터 데코레이터(param decorators)를 제공한다.
아래는 네스트에서 제공하는 데코레이터와 그들이 의미하는 Express(혹은 Fastify)의 객체(plain objects)이다.
Nest 데코레이터 | Express(Fastify) 객체 |
@Request(), @Req() | req |
@Response(), @Res() | res |
@Next() | next |
@Session() | req.session |
@Param(param?: string) | req.params / req.params[param] |
@Body(param?: string) | req.body / req.body[param] |
@Query(param?: string) | req.query / req.query[param] |
@Headers(param?: string) | req.headers / req.headers[param] |
@Ip() | req.ip |
@HostParam() | req.hosts |
커스텀 데코레이터
네스트에서 제공하는 데코레이터들 뿐만 아니라, 직접 커스텀 데코레이터를 만들어 사용할 수 있다.
node.js 에서는 request 객체에 프로퍼티를 할당하여 사용하는 것이 일반적이다.
그리고 아래와 같이 각 라우트 핸들러에서 직접 그 값을 불러온다.
const user = req.user;
그런데 네스트에서는 @User()와 같은 데코레이터를 만들어
모든 컨트롤러에서 재사용한다면
코드를 더 직관적이고 가독성 좋게 만들 수 있다.
데코레이터의 정의부와
// user.decorator.ts
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
export const User = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.user;
},
);
사용부 예시이다.
원하는 곳에서 재사용이 가능하다.
@Get()
async findOne(@User() user: UserEntity) {
console.log(user);
}
커스텀 데코레이터에 데이터 전달하기
생성한 데코레이터가 특정 조건에 따라 동작이 달라진다면,
데코레이터 팩토리 함수의 인자로 data 파라미터를 넘길 수 있다.
예시로 request 객체에서 key로 프로퍼티를 가져오는 커스텀 데코레이터를 살펴보자.
예를 들어 우리 서버의 인증 계층은 request를 검증하고, user entity를 request 객체에 넣는 역할을 한다.
그 인증된 request에 포함된 user entity는 아래와 같다.
{
"id": 101,
"firstName": "Alan",
"lastName": "Turing",
"email": "alan@email.com",
"roles": ["admin"]
}
그럼 프로퍼티 이름을 키로 받고, 그에 따른 값이 있다면 값을 반환하는 데코레이터를 만들어보자.
// user.decorator.ts
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;
},
);
아래는 컨트롤러에서 특정 프로퍼티를 @User() 데코레이터로 접근하는 방법이다.
@Get()
async findOne(@User('firstName') firstName: string) {
console.log(`Hello ${firstName}`);
}
다른 프로퍼티를 가져오려면 다른 key를 사용하면 된다.
user 객체가 deep하거나 복잡하다면
이러한 방식으로 request 핸들러 구현체를 더 쉽고 가독성 높게 만들 수 있다.
커스텀 데코레이터 파이프와 함께 사용하기
커스텀 param 데코레이터는 네스트 빌트인 데코레이터들(@Body(), @Param() 등)과 동일한 방식으로 취급된다.
따라서 파이프도 커스텀 데코레이터에 사용할 수 있다.
@Get()
async findOne(
@User(new ValidationPipe({ validateCustomDecorators: true })),
user: UserEntity,
){
console.log(user);
}
위 경우에 validateCustomDecorators 옵션은 항상 true여야 한다.
ValidationPipe의 디폴트 설정으로는 커스텀 데코레이터의 인자를 검증하지 않는다.
데코레이터 결합하기
네스트는 여러 데코레이터를 결합할 수 있는 헬퍼 메서드들을 제공하고 있다.
예를 들어, 인증과 관련된 모든 데코레이터들을 하나의 데코레이터로 합치고 싶다면
아래와 같이 구성할 수 있다.
// auth.decorator.ts
import { applyDecorators } from '@nestjs/common';
export function Auth(...roles: Role[]){
return applyDecorators(
SetMetaData('roles', roles),
UseGuards(AuthGuard, RolesGuard),
ApiBearerAuth(),
ApiUnauthorizedResponse({ description: 'Unauthorized' }),
);
}
그럼 아래와 같이 @Auth() 데코레이터 하나로
네 개의 데코레이터가 적용된 효과를 볼 수 있다.
@Get('users')
@Auth('admin')
findAllUsers(){}
주의할 점은, @nestjs/swagger 패키지의 @ApiHideProperty() 데코레이터는
다른 데코레이터의 하위 구성 데코레이터로 들어갈 수 없고,
applyDecorators 함수와 사용하면 정상 동작하지 않는다.
참고 자료
'Node.js > NestJS' 카테고리의 다른 글
NestJS 커스텀 프로바이더 사용법 (4) | 2025.01.05 |
---|---|
NestJS API 응답에서 불필요한 프로퍼티를 제외하는 방법 (2) | 2024.08.03 |
NestJS 전역 CacheManager로 Redis 사용하기 (3) | 2024.07.06 |
[TIL][NestJS] @Param() 데코레이터 사용 시 주의사항 (+Typeorm) (1) | 2023.05.19 |
[NestJS] 각종 트러블 슈팅 (0) | 2023.05.18 |