Skip to content

Pipe

NestJs Pipe

pipe의 사용목적

pipe의 사용

공식홈페이지에는 여러 사용방법이 나와 있는데 그 중에 dto와 데코레이터와 바인딩되는 방법을 사용할 예정입니다.
NestJs에서 제공하는 ValidationPipe를 main.ts에 global로 설정하면 준비는 끝납니다.

  • dto를 사용할 경우 class-validator와 class-transform를 이용하게 됩니다.
  • 데코레이터와 바인딩되는 pipe의 종류
    • ParseIntPipe: 입력 값을 정수로 변환합니다. 변환이 가능하지 않은 경우, 예외를 발생시킵니다.
    • ParseFloatPipe: 부동소수점 숫자로 변환합니다. 변환이 불가능한 경우 예외를 발생시킵니다.
    • ParseBoolPipe: 입력 값을 불리언 값으로 변환합니다. true, false, 1, 0 외의 값은 예외를 발생시킵니다.
    • ParseArrayPipe: 입력 값을 배열로 변환합니다. 선택적으로, 배열 내 항목의 타입도 검사할 수 있습니다.
    • ParseUUIDPipe: 입력 값을 UUID로 변환합니다. 유효하지 않은 UUID 형식인 경우 예외를 발생시킵니다.
    • ParseEnumPipe: 입력 값을 특정 열거형의 값으로 변환합니다. 입력 값이 해당 열거형에 정의된 값이 아닌 경우 예외를 발생시킵니다.
    • DefaultValuePipe: 입력 값의 default를 지정할 수 있습니다. null 또는 undefined을 수신하면 예외를 발생시킵니다.
    • ParseFilePipe: 파일 업로드 요청을 처리하고, 파일의 유효성을 검사합니다. 파일 크기 제한이나 MIME 타입 검사 등의 옵션을 설정할 수 있습니다.

구현

Github Link

  1. 설치
sh
npm i --save class-validator class-transformer
  1. main.ts
typescript
nestLib() {
  this.server.useGlobalPipes(
    new ValidationPipe({
      transform: true, // 요청 데이터를 해당 타입으로 변환
      skipNullProperties: false, // null 값을 건너뛰지 않음
      skipMissingProperties: false, // 누락된 속성을 건너뛰지 않음
      skipUndefinedProperties: false, // 정의되지 않은 속성을 건너뛰지 않음
      forbidUnknownValues: false, // 알 수 없는 속성이 있는 경우 예외 발생
      whitelist: false, // 허용되지 않은 속성이 있는 경우 제거
      forbidNonWhitelisted: false, // 허용되지 않은 속성이 있는 경우 예외 발생
    }),
  );
}

async bootstrap() {
  this.policy();
  this.session();
  this.nestLib();
  await this.server.listen(this.port);
  this.url = await this.server.getUrl();
}

여러 옵션이 있지만 일단 주된 옵션을 기재해 놓았습니다.
원한다면 좀 더 상세히 설정이 가능합니다.

  1. cats.dto.ts
typescript
import { IsNotEmpty, IsNumber, IsOptional, IsString } from "class-validator";

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

  @IsNotEmpty()
  @IsNumber()
  age: number;

  @IsNotEmpty()
  @IsString()
  breed: string;
}

export class UpdateCatDto {
  @IsOptional()
  @IsString()
  name: string;

  @IsOptional()
  @IsNumber()
  age: number;

  @IsOptional()
  @IsString()
  breed: string;
}

class validator는 여러가지 type의 validation을 지원합니다.
IsOptional은 만약 해당 key값이 있으면 validation을 하겠다는 것입니다.
이외에도 validationIf로 조건을 걸거나 nested로 array이나 object 안의 deep한 곳까지 validation이 가능합니다.

  1. cats.controller.ts
typescript
import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Body,
  Param,
  ParseIntPipe,
} from "@nestjs/common";
import { CreateCatDto, UpdateCatDto } from "./dto/cats.dto";

@Controller("cats")
export class CatsController {
  @Post()
  create(@Body() createCatDto: CreateCatDto) {
    return `This action adds a new cat ${createCatDto.name}`;
  }

  @Get()
  findAll() {
    return `This action returns all cats`;
  }

  @Get(":id")
  findOne(@Param("id", new ParseIntPipe()) id: number) {
    return `This action returns a cat ${id}`;
  }

  @Put(":id")
  update(
    @Param("id", new ParseIntPipe()) id: number,
    @Body() updateCatDto: UpdateCatDto
  ) {
    return `This action updates a cat ${id}`;
  }

  @Delete(":id")
  remove(@Param("id", new ParseIntPipe()) id: number) {
    return `This action removes a cat ${id}`;
  }
}

여기서는 param이 id 1개 임으로 간단하게 ParseIntPipe로 validation과 transform을 했지만
param의 객체가 커진다면 dto로 만들어 사용하는 것도 좋습니다.

  1. 실행

postman 혹은 vscode의 thunder client를 이용하거나 cli에서 curl 명령어로
http://localhost:3000/api/cats/1 이렇게 get 요청을 보내면
This action returns a cat 1 이렇게 return 됩니다.

만약 http://localhost:3000/api/cats/abc 이렇게 보낸다면 아래와 같이 return 됩니다.

json
{
  "message": "Validation failed (numeric string is expected)",
  "error": "Bad Request",
  "statusCode": 400
}

Post로도 보내 봅시다. 아래와 같이 http://localhost:3000/api/cats 여기로 post 요청을 보내면..

json
{
  "name": "시비시바",
  "age": 4,
  "breed": "다 잘먹어요"
}

return value: This action adds a new cat 시비시바

만약 breed를 뺴고 보내봅시다. 그럼 아래와 같이 return 됩니다.

json
{
  "message": ["breed must be a string", "breed should not be empty"],
  "error": "Bad Request",
  "statusCode": 400
}