Pipes
Built-in pipes
ValidationPipeParseIntPipeParseFloatPipeParseBoolPipeParseArrayPipeParseUUIDPipeParseEnumPipeDefaultValuePipeParseFilePipeBinding pipes
@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
return this.catsService.findOne(id);
}@Patch('bulk')
async updateBulkCoupons(
@Body(new ParseArrayPipe({ items: PatchCouponsRequestDto }))
patchCouponsRequestDto: PatchCouponsRequestDto[],
) { ... }
}Custom pipes
export interface ArgumentMetadata {
readonly type: 'body' | 'query' | 'param' | 'custom';
readonly metatype?: Type<any>;
readonly data?: string;
}@Controller('cats')
export class CatsController {
@Post()
async create(@Body() createCatDto: CreateCatDto) {
// DTO를 클래스로 사용했으므로 이후의 작업에 필요한 타입 정보를 활용할 수 있습니다.
}
}
Object schema validation
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { ObjectSchema } from 'joi';
@Injectable()
export class JoiValidationPipe implements PipeTransform {
constructor(private schema: ObjectSchema) {}
transform(value: any, metadata: ArgumentMetadata) {
const { error } = this.schema.validate(value);
if (error) {
throw new BadRequestException('Validation failed');
}
return value;
}
}
const createCatSchema = Joi.object({
name: Joi.string().required(),
age: Joi.number().required(),
breed: Joi.string().required(),
})
export interface CreateCatDto {
name: string;
age: number;
breed: string;
}@Post()
@UsePipes(new JoiValidationPipe(createCatSchema))
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}Class validator
import { IsString, IsInt } from 'class-validator';
export class CreateCatDto {
@IsString()
name: string;
@IsInt()
age: number;
@IsString()
breed: string;
}
import { PipeTransform, Injectable, ArgumentMetadata, BadRequestException } from '@nestjs/common';
import { validate } from 'class-validator';
import { plainToInstance } from 'class-transformer';
@Injectable()
export class ValidationPipe implements PipeTransform<any> {
async transform(value: any, { metatype }: ArgumentMetadata) {
// metatype이 존재하고 유효성 검사가 필요하다면, plainToInstance 함수를 이용하여 사용자로부터 받은 데이터(value)를 해당 metatype의 인스턴스로 변환.
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToInstance(metatype, value);
// validate 함수를 이용하여 데코레이터 기반 유효성 검사실행
const errors = await validate(object);
if (errors.length > 0) {
throw new BadRequestException('Validation failed');
}
return value;
}
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
Global scoped pipes
```tsx
import { Module } from '@nestjs/common';
import { APP_PIPE } from '@nestjs/core';
@Module({
providers: [
{
provide: APP_PIPE,
useClass: ValidationPipe,
},
],
})
export class AppModule {}
```transform: true, // 파이프가 객체를 DTO클래스의 인스턴스로 자동 변환한다. 런타임에도 해당 타입의 안전성 보장
whitelist: true, // DTO에 정의되지 않은 프로퍼티가 객체에 있는 경우 자동 제거.
stopAtFirstError: true, // 오류가 발생하면 유효성 검사가 중지된다.
The built-in ValidationPipe
transform: 이 옵션은 Boolean 값으로, true로 설정하면 파이프가 객체를 DTO 클래스의 인스턴스로 자동 변환합니다. 이렇게 하면 런타임에도 해당 타입의 안전성을 보장할 수 있습니다.validateCustomDecorators: 이 옵션은 Boolean 값으로, true로 설정하면 사용자 정의 데코레이터에 대한 유효성 검사도 수행합니다.skipMissingProperties: 이 옵션은 Boolean 값으로, true로 설정하면 객체의 일부 프로퍼티가 누락된 경우 해당 프로퍼티를 검증에서 건너뜁니다.exceptionFactory: 이 옵션은 함수를 받아, 유효성 검증에서 에러가 발생했을 때 반환할 예외를 사용자가 직접 정의할 수 있게 해줍니다.whitelist: 이 옵션은 Boolean 값으로, true로 설정하면 DTO에 정의되지 않은 프로퍼티가 객체에 있을 경우 해당 프로퍼티를 자동으로 제거합니다.forbidNonWhitelisted: 이 옵션은 Boolean 값으로, true로 설정하면 DTO에 정의되지 않은 프로퍼티가 객체에 있을 경우 에러를 발생시킵니다.forbidUnknownValues: 이 옵션은 Boolean 값으로, true로 설정하면 유효성 검사 도중 알 수 없는 값이 발견될 경우 에러를 발생시킵니다.dismissDefaultMessages: 이 옵션은 Boolean 값으로, true로 설정하면 기본 유효성 검사 메시지를 비활성화합니다.validationError: 이 옵션은 { target: boolean, value: boolean } 형태의 객체를 받아, 각각 ValidationError 객체에 target과 value 속성을 포함할지 여부를 지정합니다.groups: 이 옵션은 문자열의 배열을 받아, 그룹화된 속성에 대한 유효성 검사를 수행할 때 사용됩니다.always: 이 옵션은 Boolean 값으로, true로 설정하면 일부 조건에 따라 속성이 유효성 검사에서 제외될 때 이를 무시하고 항상 유효성 검사를 수행합니다.message: 이 옵션은 문자열이나 함수를 받아, 유효성 검사 에러 메시지를 재정의합니다.errorHttpStatusCode: 이 옵션은 숫자를 받아, 유효성 검사 에러가 발생Transformation use case
@Patch('bulk')
async updateBulkCoupons(
@Body(new ParseArrayPipe({ items: PatchCouponsRequestDto }))
patchCouponsRequestDto: PatchCouponsRequestDto[],
) {
const updatedCoupons = await this.couponsService.updateBulkCoupons(
patchCouponsRequestDto,
);
return plainToInstance(
PatchCouponsResponseDto,
{
data: updatedCoupons,
totalCount: updatedCoupons.length,
},
{ excludeExtraneousValues: true },
);
}
Providing defaults
@Get()
async findAll(
@Query('activeOnly', new DefaultValuePipe(false), ParseBoolPipe) activeOnly: boolean,
@Query('page', new DefaultValuePipe(0), ParseIntPipe) page: number,
) {
return this.catsService.findAll({ activeOnly, page });
}