본문 바로가기
NestJS

NestJS - Custom Decorator

by Programmer.Junny 2025. 2. 27.

데코레이터(Decorator) 란

데코레이터는 특정 대상(클래스, 메서드, 프로퍼티, 매개변수 등)에 “붙여서” 해당 대상의 동작을 수정하거나, 부가적인 정보를 첨부할 수 있는 함수이다. 이는 일종의 주석처럼 보이지만, 실제로 실행 시점에 코드를 변형하거나 부가 기능을 추가하는 역할을 한다.

@Put(':id')
putPost(
@Param('id', ParseIntPipe) id: number,
@Body('title') title?: string,
@Body('content') content?: string,
)

앞서 메서드의 파라미터에 @Body, @Param을 넣는 것들도 데코레이터에 해당된다.

커스텀 데코레이터 만들기

// 3) POST /posts
// post를 생성한다.
@Post()
postPosts(
@Body('authorId') authorId: number,
@Body('title') title: string,
@Body('content') content: string,
) {
return this.postsService.createPost(authorId, title, content);
}

앞서 Post를 생성하는 로직에서 문제가 하나 있다.

@Body('authorId') authorId: number,

사용자 Id를 직접 넣는 부분인데 문제는 포스팅 시 authorId를 본인이 아닌 다른 사용자의 Id를 넣어 작성할 수 있다는 점이다.

본인인지 확인하도록 변경 (AccessTokenGuard 추가)

앞서 본인인지 확인을 하도록 하는 로직은 AccessTokenGuard로 구현이 가능하다.

// 3) POST /posts
// post를 생성한다.
@Post()
@UseGuards(AccessTokenGuard)
postPosts(
@Body('authorId') authorId: number,
@Body('title') title: string,
@Body('content') content: string,
) {
return this.postsService.createPost(authorId, title, content);
}

Guard로 AccessToken의 변조를 확인하여 본인인지 확인을 하고 있지만 여전히 createPost로 인해 authorId를 사용하고 있다. 이 부분을 위해 커스텀 데코레이터를 구현해보도록 하자.

import { createParamDecorator, ExecutionContext, InternalServerErrorException } from "@nestjs/common";
import { UsersModel } from "../entities/users.entity";
export const User = createParamDecorator((data: keyof UsersModel | undefined, context: ExecutionContext) => {
const req = context.switchToHttp().getRequest();
const user = req.user as UsersModel;
/**
* User Decorator는 AccessTokenGuard와 같이 사용하므로
* user가 없는 경우는 서버측에 문제가 있는 경우이다.
*/
if(!user) {
throw new InternalServerErrorException('User 데코레이터는 AccessTokenGuard와 함께 사용해야 합니다. Request에 user 프로퍼티가 존재하지 않습니다.');
}
if(data) {
return user[data];
}
return user;
})

users에 decorator 폴더를 만들어 user.decorator.ts 라는 이름으로 파일을 만든 후 위와 같이 작성한다.

변수명 User의 앞자가 대문자인 경우는 보통 데코레이터는 대문자로 시작하도록 되어있기 때문이다.

createParamDecorator 는 NestJS에서 제공하는 메서드이므로 자동으로 Import 된다.

(data: keyof UsersModel | undefined, context: ExecutionContext) => {

createParamDecorator 매개변수는 콜백을 입력한다. 콜백에 첫 번째는 사용자가 지정할 수 있는 data를 입력하며 두 번째 매개변수는  context: ExecutionContext를 입력한다.

const req = context.switchToHttp().getRequest();
const user = req.user as UsersModel;

context를 받으므로 req 요청 객체를 받아올 수 있다.

AccesstokenGuard 를 선행해서 실행하게 되며, 이 부분으로 인해 req.user에 user가 있는 것을 알 수 있다.

/**
* User Decorator는 AccessTokenGuard와 같이 사용하므로
* user가 없는 경우는 서버측에 문제가 있는 경우이다.
*/
if(!user) {
throw new InternalServerErrorException('User 데코레이터는 AccessTokenGuard와 함께 사용해야 합니다. Request에 user 프로퍼티가 존재하지 않습니다.');
}

만약 user가 없는 경우라면 AccessTokenGuard를 선행해서 실행하지 않았다고 볼 수 있거나, 서버로직에 문제가 있다고 볼 수 있다.

if(data) {
return user[data];
}

user는 UsersModel이므로 UsersModel 내의 key로 불러올 수 있다. 위의 코드에서 data의 타입은 keyof UsersModel인데 이는 UsersModel의 key값만을 넣도록 되어 있다.

// 3) POST /posts
// post를 생성한다.
@Post()
@UseGuards(AccessTokenGuard)
postPosts(
@User('id') userId: number,
@Body('title') title: string,
@Body('content') content: string,
) {
return this.postsService.createPost(userId, title, content);
}

이렇게 만들어진 데코레이터를 적용할 수 있다.

@User('id') userId: number,

우리는 첫 번째 매개변수로 UsersModel의 key값을 넣도록 지정하였으니 'id'를 넣어준다. 그리고 userId: number 으로 지정하면 UsersModel의 Id를 가져오게 된다.

'NestJS' 카테고리의 다른 글

NestJS - Class Validation과 DTO  (0) 2025.02.28
Postman 심화기능  (0) 2025.02.27
NestJS - Guard  (0) 2025.02.27
NestJS - Pipe  (0) 2025.02.26
VSC 디버거 사용하기  (0) 2025.02.26

최근댓글

최근글

skin by © 2024 ttuttak