NestJS - Pipes

수현·2023년 11월 4일

NestJS

목록 보기
2/3

Pipe란

Nest에서 파이프는 주로 두 가지 기능을 한다.

  1. 데이터 형 변환
    : ParseIntPipe, ParseFloatPipe, ParseBoolPipe, ParseArrayPipe 등
  2. 유효성 검사
    : 데이터를 평가하고 유효한 경우 데이터 그대로 전달, 유효하지 않은 경우 예외 발생

Nest에는 미리 정의되어 있어 사용 가능한 9개의 파이프가 있다.

  • ValidationPipe
  • ParseIntPipe
  • ParseFloatPipe
  • ParseBoolPipe
  • ParseArrayPipe
  • ParseUUIDPipe
  • ParseEnumPipe
  • DefaultValuePipe
  • ParseFilePipe

이름으로 기능을 유추할 수 있듯이 유효성을 검사하는 ValidationPipe와 나머지 데이터 형에 대한 파이프들이다.

$ npm install class-validator class-transformer

위의 명령어로 두 가지 모듈을 설치한 후 사용이 가능하다.


Binding pipes

파이프를 사용하기 위해서는 파이프를 적절한 context에 바인딩해야 한다. 크게 Handler-level Pipes, Parameter-level Pipes, Global-level Pipes 로 나눌 수 있다.

Handler-level Pipes

@Post()
@UsePipes(pipe)
createBoard(@Body('title') title, @Body('content') content): Board {
  ...
}

@UsePipe() decorator를 이용하여 해당 handler의 모든 파라미터에 파이프를 적용할 수 있다.

Parameter-level Pipes

@Post()
createBoard(@Body('title', ParameterPipe) title,
            @Body('content') content
) {
  ...
}

parameter 옆에 작성함으로써 특정한 파라미터에만 파이프를 적용할 수 있다.

Global-level Pipes

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(GlobalPipes);
  await app.listen(3000);
}
bootstrap();

이 파이프는 애플리케이션 레벨의 파이프로 클라이언트에서 들어오는 모든 요청에 적용된다. 가장 상단인 main.ts에 작성하면 된다.


데이터 유효성 검증

데이터의 유효성을 검증하기 위해 ValidationPipe를 사용해보겠다. class-validator 모듈을 설치했다면 다양한 validation-decorators를 사용할 수 있다. class-validator GitHub을 참고하자!

// dto/createBoard.dto.ts
import { IsNotEmpty } from 'class-validator';

export class CreateBoardDto {
  @IsNotEmpty()
  title: string;

  @IsNotEmpty()
  content: string;
}

먼저 위와 같이 DTO에 원하는 validation decorator를 달아준다.

@Controller('boards')
export class BoardsController {
  constructor(private boardsService: BoardsService) {}

  @Post()
  @UsePipes(new ValidationPipe())
  createBoard(@Body() createBoardDto: CreateBoardDto): Board {
    return this.boardsService.creatPost(createBoardDto);
  }
}

그리고 ValidationPipe를 적용하기 위해 Handler에 @UsePipes decorator안에 ValidationPipe의 인스턴스를 인자로 넣어준다. 물론 main.ts에서 애플리케이션 레벨로 관리할 수도 있다.
이렇게 하면 title이나 content의 값이 빈 채로 들어오면 에러를 발생시킨다.


Custom Pipe

Pipe를 직접 정의하여 사용할 수 있는데 @Injectable() decorator가 달린 클래스로 정의하며, PipeTransform interface를 implements해야 한다.

// validation.pipe.ts
import { PipeTransform, Injectable, ArgumentMetadata } from '@nestjs/common';

@Injectable()
export class ValidationPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    // code
    return value;
  }
}

모든 파이프는 PipeTransform interface대로 transform() method를 정의해야 한다. arguments로 value와 metadata가 있는데, value는 처리되는 인자의 값이고 metadata는 그 값에 대한 메타데이터이다. metadata의 ArgumentMetadata 타입은 아래와 같다.

export interface ArgumentMetadata {
  type: 'body' | 'query' | 'param' | 'custom';
  metatype?: Type<unknown>;
  data?: string;
}

transform()에서 파이프에서 수행해야 할 작업을 정의할 수 있다.

export class BoardStatusValidationPipe implements PipeTransform {
  readonly StatusOptions = [BoardStatus.PRIVATE, BoardStatus.PUBLIC];

  transform(value: any) {
    value = value.toUpperCase();

    if (!this.isStatusValid(value)) {
      throw new BadRequestException(`${value} isn't in the status options`);
    }
    return value;
  }

  private isStatusValid(status: any) {
    const index = this.StatusOptions.indexOf(status);
    return index !== -1;
  }
}

transform() method에서 return된 값은 handler로 전해지고 예외가 발생하면 바로 클라이언트로 전해진다.


참고 자료

https://docs.nestjs.com/pipes
https://www.youtube.com/watch?v=3JminDpCJNE&t=6261s

profile
실패와 성장을 기록합니다 🎞️

0개의 댓글