NestJS Tutorial (7) - Pipe

Hoony·2023년 6월 27일
0

NestJS

목록 보기
7/8


Pipe

Pipe는 크게 2가지 종류가 있습니다.

  • Transform Pipe : 입력 데이터를 원하는 형식으로 변환
  • Validation Pipe : 입력 데이터를 평가하고 유효한 경우 데이터를 전달, 그렇지 않으면 예외 발생


Transform Pipe

NestJS에는 여러 내장된 Pipe Class가 존재합니다.

이를 통하여 입력 데이터를 원하는 형식으로 바꿀 수 있습니다.

@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
  return this.catsService.findOne(id);
}
  • 만약 입력된 데이터가 바꿀 수 없는 형태면 에러를 발생시킵니다.


Pipe 동작 제어

옵션 매개변수를 통해 Pipe 동작을 다음과 같이 제어할 수 있습니다.

@Get(':id')
async findOne(
  @Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
  id: number,
) {
  return this.catsService.findOne(id);
}


Validation Pipe - Custom Pipe

스키마를 검증하는 파이프를 구축해보겠습니다.

NestJS 에 내장된 PipeTransform 를 구현하여 사용합니다.

먼저, schema object 사용하기 위해 Joi library를 설치합니다.

$ npm install --save joi

이후 Joi Object를 이용하여 schema를 정의합니다.

import * as Joi from 'joi';

export const createCatSchema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().required(),
  breed: Joi.string().required(),
});

export interface CreateCatDto {
  name: string;
  age: number;
  breed: string;
}

마지막으로 Validation Pipe를 생성하고 바인딩해줍니다.

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

@Injectable()
export class JoiValidationPipe implements PipeTransform {
  constructor(private schema: ObjectSchema) {}

  transform(value: any, metadata: ArgumentMetadata) {
    const { error } = this.schema.validate(value);
    if (error) {
      throw new BadRequestException('Validation failed');
    }
    return value;
  }
}

@UsePipes 데코레이터를 통해 ValidationPipe를 바인딩해줍니다.

이때 매개변수로 검증을 진행할 schema를 넘겨줍니다.

@Post()
@UsePipes(new JoiValidationPipe(createCatSchema))
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}


Validation Pipe - Class validator

또 다른 방법으로, class-validator library 를 사용하여 유효성 검사 가능합니다.

설치

$ npm i --save class-validator class-transformer


클래스 생성

import { IsString, IsInt } from 'class-validator';

export class CreateCatDto {
  @IsString()
  name: string;

  @IsInt()
  age: number;

  @IsString()
  breed: string;
}


파이프 생성

import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';@Injectable()
export class ValidationPipe implements PipeTransform<any> {
  async transform(value: any, { metatype }: ArgumentMetadata) {
    if (!metatype || !this.toValidate(metatype)) {
      return value;
    }
    const object = plainToInstance(metatype, value);
    const errors = await validate(object);
    if (errors.length > 0) {
      throw new BadRequestException('Validation failed');
    }
    return value;
  }private toValidate(metatype: Function): boolean {
    const types: Function[] = [String, Boolean, Number, Array, Object];
    return !types.includes(metatype);
  }
}


파이프 바인딩

@Post()
async create(
  @Body(new ValidationPipe()) createCatDto: CreateCatDto,
) {
  this.catsService.create(createCatDto);
}


전역 범위 파이프 바인딩

위의 예제에서는 컨트롤러 메서드 단위로 파이프를 바인딩했습니다.

같은 파이프 클래스를 계속 바인딩하는 것은 재사용 측면에서 좋지 않으므로, 이를 전역 단위로 바인딩합니다.

main.ts

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

종속성 주입 측면에서 useGlobalPipes()바인딩이 모듈의 컨텍스트 외부에서 수행되었으므로 모듈 외부에서 등록된 전역 파이프(위의 예에서와 같이)는 종속성을 주입할 수 없습니다. 이 문제를 해결하기 위해 다음 구성을 사용하여 모든 모듈에서 직접 글로벌 파이프를 설정할 수 있습니다.

import { Module } from '@nestjs/common';
import { APP_PIPE } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_PIPE,
      useClass: ValidationPipe,
    },
  ],
})
export class AppModule {}
profile
Just Do it!

0개의 댓글

관련 채용 정보