NestJS - pipe 사용법

DaeChan Jo·2024년 1월 14일
0

nest.js

목록 보기
2/3

pipe

파이프는 일반적으로 다음 두 가지 사용 사례가 있다.

  • 변환 : 데이터를 원하는 형식으로 변환
  • 유효성 검사 : 데이터를 평가하고 유효하지 않다면 예외 발생

express에선 하나하나 미들웨어로 만들어야했다면 nest.js에선 자체적으로 제공하는 빌트인 파이프를 데코로 붙여서 사용하기만 하면 된다 (편-안)

Validation Pipe

예를 들어 게시글을 작성하는 api의 컨트롤러에서 입력받은 데이터를 검증하고자 한다면 다음과 같이 할 수 있다.

  @Post()
  @UsePipes(new ValidationPipe())
  async createPost(
    @Body() postContent: PostContentDto,
  ): Promise<PostDto> {
    ...
  }

@Body 데코레이터는 HTTP 요청 본문에 있는 값을 메서드의 인자로 바인딩하는 역할을 하고 이 때 바인딩된 DTO 객체는 @UsePipes(new ValidationPipe()) 데코레이터에 의해 유효성 검사를 실행하기 된다.

즉, PostContentDto 클래스에 정의된 @IsString(), @IsNotEmpty() 등의 데코레이터에 부합하는지 검사하게 된다.

export class PostContentDto {
  @ApiProperty()
  @IsNotEmpty()
  @IsString()
  @Length(1, 50)
  title: string;

  @ApiProperty()
  @IsNotEmpty()
  @IsString()
  @Length(1, 1000)
  content: string;
}



변환

express라면 입력받은 데이터를 가공하거나 형변환을 하려면 함수 내부에서 코드를 작성해야했더라면 nest.js에서는 마찬가지로 간단한 파이프 데코로 처리할 수 있어 보다 간결한 컨트롤러를 구현할 수 있다.
하지만 개인적인 생각으로 형변환에 관련된 빌트인 파이프들은 알맞게 바로 사용할 수 없는 경우가 많아서 직접 만들어서 쓴 경우가 많았던것 같다.

사용법은 다음과 같다.

  @Post()
  @UsePipes(new ValidationPipe())
  @UseGuards(AuthGuard('jwt'))
  async createComment(
    @Request() req: RequestWithUser,
    @Body() commentContent: CommentContentDto,
    @Query('postId', ParseIntPipe) postId: number,
    @Optional() @Query('parentId', OptionalIntPipe) parentId?: number,
  ): Promise<CommentDto> {
    ...
  }

ParseIntPipe 는 전달받은 문자열인 postId를 10진수로 변환해주는 빌트인 파이프이다.
하지만 쿼리중 옵션으로 받게되는 parentId에도 ParseIntPipe를 적용하면 해당 값이 없는 경우 변환할 수 없으므로 예외를 발생시키게 된다. 이런 경우 파이프를 커스텀해서 사용해야한다.

import { ArgumentMetadata, Injectable, PipeTransform, BadRequestException } from '@nestjs/common';

@Injectable()
export class OptionalIntPipe implements PipeTransform {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  transform(value: string, metadata: ArgumentMetadata) {
    if (!value) return null;
    const val: number = parseInt(value, 10);
    if (isNaN(val)) {
      throw new BadRequestException('Validation failed (numeric string is expected)');
    }
    return val;
  }
}

만일 value가 null 또는 undefined라면 null을 반환하도록 하는데 이는 선택적인 값을 처리하기 위함이다.
value가 존재하면 해당 값을 10진수 숫자로 변환하고 반환한다. 만약 NaN이라면, 즉 숫자로 변환할 수 없는 문자열이라면 예외를 발생시키도록 만든 파이프이다.


파이프의 동작 방식

파이프는 예외 구역 내부에서 실행된다. 이는 파이프가 예외를 발생시킬 때 예외 계층(전역 예외 필터 및 현재 컨텍스트에 적용되는 모든 예외 필터 ) 에 의해 처리된다는 것을 의미한다.

"예외 구역"은 파이프가 실행되는 코드 영역을 지칭한다. 파이프는 요청 처리 파이프라인의 일부로서, 데이터를 변환하거나 유효성을 검사하는 역할을 하게되고 이 과정에서 파이프 내부에서 예외가 발생하면 예외는 NestJS의 "예외 계층"에 의해 처리된다.

"예외 계층"이란 전역 예외 필터와 현재 컨텍스트(context)에 적용되는 모든 예외 필터를 포함하는 계층을 의미한다. 이 계층은 애플리케이션의 예외 처리 메커니즘을 담당하며, 파이프에서 발생하는 예외를 적절히 처리하여 사용자에게 알려준다.

즉, 파이프는 컨트롤러의 메서드가 실행되기 전 유효성 검사 및 형변환을 수행하고 이 과정에서 예외가 발생하게되면 컨트롤러 메서드는 실행되지 않는다.

profile
BackEnd Developer

0개의 댓글