1. 서론
pipe
는 @Injectable()
데코레이터가 지정된 클래스로, PipeTransform
인터페이스를 implements 한 것이다.
pipe를 사용하는 이유는 2가지가 있다.
transformation(변환): 입력된 데이터를 원하는 형태로 변환한다(예: 문자열을 정수로).
validation(검증): 입력 데이터를 평가하고 유효한 경우 그대로 전달한다. 데이터가 잘못된 경우 예외를 발생시킨다.
Nest는 컨트롤러에 작성된 함수가 호출되기 전에 pipe를 삽입하고, pipe는 함수에 전달될 인수를 수신하고 이들을 처리한다.
Nest에는 즉시 사용할 수 있는 내장 pipe가 여러 개 있으며, 사용자 정의 pipe를 작성할 수도 있다.
먼저 내장 pipe부터 알아보자.
2. 내장 pipe
import { Controller, Get, Param } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getHello(@Param('id') id: any) {
return "hello"
}
}
위 코드는 id를 param으로 받아서 사용하는 예이다.
id의 타입을 출력해보면 string
타입임을 알 수 있다.
import { Controller, Get, Param } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getHello(@Param('id') id: any) {
const type = typeof id;
return { id, type };
}
}
하지만 우리는 id를 string 타입이 아니라 number
타입으로 사용해야 될 수도 있다.
그럴때마다 우리가 직접 변환하는 것이 아니라 위에서 설명했던 pipe를 사용할 수 있다.
pipe를 사용하려면, pipe 클래스의 인스턴스를 적절한 컨텍스트에 바인딩해야 한다.
그럼 타입을 정수형으로 바꿔주는 ParseIntPipe
내장 pipe를 사용해보자.
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getHello(@Param('id', ParseIntPipe) id: any) {
const type = typeof id;
return { id, type };
}
}
response를 보면 id가 number 타입으로 변환된 것을 볼 수 있다.
이것이 위에서 말했던 pipe를 사용하는 이유 중 하나인 "transformation"
이다.
그렇다면 validation은 무엇일까?
다음 사진을 살펴보자.
":id"
값에 숫자가 아니라 알파벳을 입력했더니 400 에러가 발생했다.
이렇듯 숫자가 아닌 값을 id에 입력하면 자동으로 validation error를 발생시킨다.
이것이 pipe를 사용하는 두 번째 이유 "validation"
이다.
3. 사용자 정의 pipe
그럼 이제 사용자가 정의하여 사용하는 pipe를 만들어보자
먼저 nest 명령어 nest g pipe {pipe 명}
으로 pipe 템플릿을 생성해주자.
다음과 같은 파일이 하나 생성되었을 것이다.
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class ParseStringPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
return value;
}
}
위 클래스 안에 있는 transform()
함수가 바로 값을 변환하여 반환해주는 함수이다.
1번째 인자로 이전 값을 받아서 내부 로직을 거쳐 return 되면, 그 반환된 값이 바로 변환된 값이다.
그럼 위에서 ParseIntPipe
를 통해 string 타입을 number 타입으로 바꿨으니 이번에는 number 타입을 string 타입으로 바꿔주는 pipe를 한 번 만들어보자.
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class ParseStringPipe implements PipeTransform {
transform(value: number, metadata: ArgumentMetadata) {
return `${value}`;
}
}
그리고 컨트롤러에 이 pipe를 추가해주자.
import { ParseStringPipe } from './parse-string/parse-string.pipe';
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getHello(@Param('id', ParseIntPipe, ParseStringPipe) id: any) {
const type = typeof id;
return { id, type };
}
}
그리고 response를 확인해보면 다음과 같다.