Pipe
pipe의 사용목적
- lifecycle에서 controller 직전인 5번쨰에 사용되게 됩니다.
- pipe의 사용목적은 2가지 입니다.
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 타입 검사 등의 옵션을 설정할 수 있습니다.
구현
- 설치
npm i --save class-validator class-transformer- main.ts
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();
}여러 옵션이 있지만 일단 주된 옵션을 기재해 놓았습니다.
원한다면 좀 더 상세히 설정이 가능합니다.
- cats.dto.ts
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이 가능합니다.
- cats.controller.ts
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로 만들어 사용하는 것도 좋습니다.
- 실행
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 됩니다.
{
"message": "Validation failed (numeric string is expected)",
"error": "Bad Request",
"statusCode": 400
}Post로도 보내 봅시다. 아래와 같이 http://localhost:3000/api/cats 여기로 post 요청을 보내면..
{
"name": "시비시바",
"age": 4,
"breed": "다 잘먹어요"
}
return value: This action adds a new cat 시비시바만약 breed를 뺴고 보내봅시다. 그럼 아래와 같이 return 됩니다.
{
"message": ["breed must be a string", "breed should not be empty"],
"error": "Bad Request",
"statusCode": 400
}