🗃️ 내가 다시 볼 것

[NestJS] Pipe란?

전호영 2023. 12. 24. 23:38
 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com

 

Pipe란?

Pipe란 @Injectable() 로 데코레이팅된 클래스로,  PipeTransform 인터페이스를 implements함.

Controller에 들어가기 직전의 데이터 검증 및 변환

 

Pipe의 2가지 사용 케이스

  • transformation: input data를 원하는 형식의 폼으로 변환(e.g., string → integer)
  • validation : input data가 유효한지 검사한 뒤, 유효한 경우 아무런 변경 없이 다음 로직으로 보냄. 유효하지 않은 경우 , exception을 던짐.

 

Built-in Pipes

 

예시를 봐보자!

id에 해당하는 post를 가져오는 controller이다.

  @Get(':id')
  getPost(@Param('id') id: string) {
    return this.postsService.getPostById(id);
  }

 

위 경우, id는 string으로 받아야 한다.

url에서 id 를 추출하는 것이므로, string으로 전달된다.

 

이때 id를 number로 변환하고 검증하고 싶다면, pipe를 사용한다.

  @Get(':id')
  getPost(@Param('id', ParseIntPipe) id: number) {
    return this.postsService.getPostById(id);
  }

 

위 경우, id가 잘못된 값이 들어와 number로 변환할 수 없는 값이라면, pipe가 알아서 error를 던져준다.

 

예시)

ParseIntPipe를 통해 값을 검증하는 경우

validation 실패

 

ParseIntPipe를 사용하지 않는 경우

서버 내부 에러 발생

 

에러의 내용을 통해 pipe가 실제로 값을 검증하고, 검증 실패 시 에러를 던진다는 것을 알 수 있다.

pipe를 통해 잘못된 요청이 로직에 들어가는 것을 막을 수 있다.

 

 

디버거를 통해 값을 확인해보자!

ParseIntPipe를 통해 값을 검증하는 경우

id 값에 숫자 3이 들어간 것을 볼 수 있다.

 

ParseIntPipe를 사용하지 않는 경우

id 값에 문자 '3'이 들어간 것을 볼 수 있다.

 

Custom Pipe 를 만들어보자

기본형태

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

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

 

e.g) 비밀번호가 6자 이상, 12자 이하여야 한다고 가정해보자!

이를 검증하는 custom pipe를 만들어보자.

// src/auth/pipe/password.pipe.ts
import {
  PipeTransform,
  Injectable,
  ArgumentMetadata,
  BadRequestException,
} from '@nestjs/common';

@Injectable()
export class PasswordPipe implements PipeTransform {
  transform(value: any, metadata: ArgumentMetadata) {
    if (value.toString().length < 6 || value.toString().length > 12) {
      throw new BadRequestException(
        '비밀번호는 6자 이상, 12자 이하여야 합니다.',
      );
    }

    return value.toString();
  }
}

 

// src/auth/auth.controller.ts

import { Body, Controller, Post } from '@nestjs/common';
import { AuthService } from './auth.service';
import { PasswordPipe } from './pipe/password.pipe';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('register/email')
  postRegisterEmail(
    @Body('nickname') nickname: string,
    @Body('email') email: string,
    @Body('password', PasswordPipe) password: string,
  ) {
    return this.authService.registerWithEmail({
      nickname,
      email,
      password,
    });
  }
}

 

 

Custom pipe가 잘 작동하는 것을 볼 수 있다.

 

만약 길이에 대한 제한을 일반화하고 싶으면 어떻게 해야할까?

 

Max길이에 대한 제한을 거는 pipe를 만들어보자.

// src/auth/pipe/password.pipe.ts

@Injectable()
export class MaxLengthPipe implements PipeTransform {
  constructor(public readonly length: number) {}

  transform(value: any, metadata: ArgumentMetadata) {
    if (value.toString().length > this.length) {
      throw new BadRequestException(`길이는 ${this.length} 미만이어야 합니다.`);
    }

    return value.toString();
  }
}

 

위와 같은 방식으로 MinLengthPipe도 만들 수 있을 것이다.

// src/auth/auth.controller.ts

import { Body, Controller, Post, Headers } from '@nestjs/common';
import { AuthService } from './auth.service';
import {
  MaxLengthPipe,
  MinLengthPipe,
} from './pipe/password.pipe';

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

  @Post('register/email')
  postRegisterEmail(
    @Body('nickname') nickname: string,
    @Body('email') email: string,
    @Body('password', new MaxLengthPipe(12), new MinLengthPipe(3))
    password: string,
  ) {
    return this.authService.registerWithEmail({
      nickname,
      email,
      password,
    });
  }
}

 

잘 되는지 확인해보자

최소길이 검증
최대길이 검증

 

가입이 잘 되는 것을 볼 수 있다.