2023. 6. 2. 22:33ㆍ개발 문서 번역/NestJS
이 포스팅은 「NestJS 기초실무 가이드 : 강력하고 쉬운 Node.js 웹 프레임워크로 웹사이트 만들기」
(서명: NestJS 基礎必學實務指南:使用強大且易擴展的 Node.js 框架打造網頁應用程式)
책이 출간되었습니다.
Pipe란 무엇인가요?
Pipe는 사용자가 입력한 파라미터를 처리하는데 사용됩니다.
(ex: 데이터 검증, 데이터 변경 등)
요청이 라우터 핸들러로 전달되기 전 요청 객체를 변환하거나 검사할 수 있습니다.
미들웨어와 비슷하나 미들웨어를 현재 요청이 어떤 핸들러에서 수행되고 어떤 매개변수를 갖는지에 대한
실행 context를 알지 못하기 때문에 모든 context에서 사용이 불가능합니다.
손님이 주문한 후 웨이터가 메뉴를 다시 한번 더 검사하는것과 비슷합니다.
Nest Pipe
Nest에서 Pipe는 Exception의 예외 처리를 지원합니다. Pipe에서 Exception을 던졌을 경우
이 요청은 Controller의 해당 메서드까지 가지 않습니다.
이렇게 설계하게 되면 검증을 담당하는 부분과 실행하는 부분을 효과적으로 분리할 수 있습니다.
Nest는 몇가지의 내장 Pipe를 통해 자료의 유형 변경 혹은 검증을 도와줍니다.
- ValidationPipe: 자료의 양식을 검사합니다.
- ParseIntPipe: 해당 인자가 Integer형인지를 검사하는 Pipe입니다.
- ParseBoolPipe: 해당 인자가 Boolean형인지를 검사하는 Pipe입니다.
- ParseArrayPipe: 해당 인자가 Array형인지를 검사하는 Pipe입니다.
- ParseUUIDPipe: 해당 인자가 UUID의 형식인지를 검사하는 Pipe 입니다.
- DefaultValuePipe: 해당 자료의 기본값을 설정할 때 사용되는 Pipe입니다.
Pipe 사용하기
Pipe를 사용하는 방법은 간단합니다. 라우터 파라미터의 자료형이 Integer임을 해석/검증 하고 싶다면
@Param 데코레이터를 추가하고 라우터 파라미터에 ParseIntPipe를 연결하면 됩니다.
아래 app.controller.ts를 예로 들어보겠습니다.
id를 해석시 그 id의 값이 Integer이라면 AppService에서 해당하는 User의 정보를 받아오게 하고
그 정보가 없다면 Exception을 발생시키는 예제입니다.
import { Controller, Get, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getUser(@Param('id', ParseIntPipe) id: number) {
return this.appService.getUser(id);
}
}
app.service.ts를 수정 해봅시다.
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getUser(id: number) {
const users = [
{
id: 1,
name: 'WOO'
}
];
const user = users.find(x => x.id === id);
return user || {};
}
}
웹 브라우저를 통해 http://127.0.0.1:3000/WOO에 들어가보면 오류 메세지가 출력된것을 확인할 수 있습니다.
WOO 는 Integer(정수) 형식이 아닌 문자열이니까요.
{
"statusCode": 400,
"message": "Validation failed (numeric string is expected)",
"error": "Bad Request"
}
내장 Pipe 커스텀 HttpStatusCode (Built-In Pipe Custom Http Code, 內建Pipe 自訂 HttpStatusCode)
오류 메세지를 수정하고 싶다면 ParseIntPipe에선 반드시 인스턴스화를 해야하고 관련 파라미터를 입력해야 합니다.
아래는 app.controller.ts의 예로 예제에서 발생시키고 싶은 HttpStatusCode는 406입니다.
import { Controller, Get, HttpStatus, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getUser(
@Param('id', new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE }))
id: number
) {
return this.appService.getUser(id);
}
}
http://127.0.0.1:3000/WOO 에 접속해볼까요?
{
"statusCode": 406,
"message": "Validation failed (numeric string is expected)",
"error": "Not Acceptable"
}
위와 같이 상태 코드가 406으로 바뀐것을 알 수 있습니다.
내장 Pipe 커스텀 Exception
오류 메세지를 변경하고 싶다면 exceptionFactory 파라미터를 통해 발생시킬 Exception을 지정할 수 있습니다.
아래는 app.controller.ts의 예제입니다.
import { Controller, Get, NotAcceptableException, Param, ParseIntPipe } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getUser(
@Param(
'id',
new ParseIntPipe({
exceptionFactory: () => new NotAcceptableException('숫자가 아닌 값은 변환할 수 없습니다.')
})
)
id: number
) {
return this.appService.getUser(id);
}
}
웹 브라우저를 열고 http://127.0.0.1:3000/WOO에 접속해보면...
{
"statusCode": 406,
"message": "숫자가 아닌 값은 변환할 수 없습니다.",
"error": "Not Acceptable"
}
커스텀 Pipe
내장 Pipe가 맘에 드는게 없을 경우에는 Nest에서 커스텀 Pipe를 지정할 수 있습니다.
사실 Pipe는 @Injectable의 class이며 PipeTransform 인터페이스를 구현해야 합니다.
또한 CLI를 통해 Pipe를 생성할 수 있습니다.
$ nest generate pipe <PIPE_NAME>
주의: <PIPE_NAME>은 경로를 포함할 수 있습니다. ex: pipes/parse-int
이럴 경우 src 디렉토리 아래에 경로를 포함한 Pipe가 생성됩니다.
ParseIntpipe는 pipes의 폴더 아래에 생성 해보겠습니다.
$ nest generate pipe pipes/parse-int
src 아래 pipes라는 폴더가 보일겁니다.
폴더 안에는 parse-int.pipe.ts와 parse-int.pipe.spec.ts가 생성이 된걸 확인할 수 있습니다.
아래는 Pipe의 뼈대입니다.
transform(value: any, metadata: ArgumentMetadata) 메소드를 확인할 수 있습니다.
이는 로직을 판단하는 곳이며 이 value는 들어온 값, metadata는 처리하고 있는 파라미터의 메타데이터(데이터의 데이터) 입니다.
import { ArgumentMetadata, Injectable, PipeTransform } from '@nestjs/common';
@Injectable()
export class ParseIntPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
return value;
}
}
주의: PipeTransform 뒤에는 2개의 Type을 추가할 수 있습니다.
첫번째는 T, 들어와야 하는 값이 어떤 유형이어야 하는가를 정의합니다. transform 안의 value입니다.
두번째는 R, 반환시의 자료형입니다.
parse-int.pipe.ts를 조금 수정해보겠습니다. parseInt를 거친 후의 value가 NaN인지,
NaN라면 NotAcceptableException을 던지겠습니다.
import { ArgumentMetadata, Injectable, NotAcceptableException, PipeTransform } from '@nestjs/common';
@Injectable()
export class ParseIntPipe implements PipeTransform<string, number> {
transform(value: string, metadata: ArgumentMetadata) {
const integer = parseInt(value);
if ( isNaN(integer) ) {
throw new NotAcceptableException('숫자가 아닙니다.');
}
return integer;
}
}
다음으로 app.controller.ts를 수정 해서 우리가 만든 ParseIntPipe 커스텀 파이프를 적용시켜 보겠습니다.
import { Controller, Get, Param } from '@nestjs/common';
import { AppService } from './app.service';
import { ParseIntPipe } from './pipes/parse-int.pipe';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get(':id')
getUser(
@Param('id', ParseIntPipe) id: number
) {
return this.appService.getUser(id)
}
}
브라우저를 열고 http://127.0.0.1:3000/WOO에 접속하면 아래와 같은 결과를 확인할 수 있습니다.
{
"statusCode": 406,
"message": "숫자가 아닙니다.",
"error": "Not Acceptable"
}
마치며
Pipe는 자료의 유효성 검사에서 실용적인 기능중 하나입니다. 객체 클래스의 자료는 어떻게 검증할까요?
이 부분은 다음 포스팅에서 설명하도록 하겠습니다. 오늘의 학습 요약본입니다.
1. Pipe는 자료의 유효성 검증 및 자료형 변환에 쓰입니다.
2. Nest는 6개의 내장 Pipe를 제공합니다.
3. 내장 Pipe는 Http Staus Code와 Exception을 커스텀할 수 있습니다.
4. Pipe는 @Injectable의 class이며 PipeTransform 인터페이스를 구현해야 합니다.
'개발 문서 번역 > NestJS' 카테고리의 다른 글
NestJS 帶你飛! 시리즈 번역 11# Middleware (0) | 2023.06.04 |
---|---|
NestJS 帶你飛! 시리즈 번역 10# Pipe (하) (0) | 2023.06.03 |
NestJS 帶你飛! 시리즈 번역 08# Exception & Exception filters (0) | 2023.06.01 |
NestJS 帶你飛! 시리즈 번역 07# Provider (하) (0) | 2023.05.31 |
NestJS 帶你飛! 시리즈 번역 06# Provider (상) (0) | 2023.05.31 |