[NestJS] Pipes
Pipe는 Controller arguments에 값을 전달받을떄 사용하며,
아래의 2개의 처리를 함.
1. transformation: 입력 데이터를 원하는 형식으로 변환
2. Validation: 입력 데이터를 평가하고 유효한 경우 변경하지 않고 그대로 전달. 그렇지 않으면 예외 발생
😶 Pipe 동작 시점
Controller가 호출되기 전, Nest는 파이프를 삽입하고
파이프는 arguments를 수신하여 동작한다.
transformation, Validation 작업은 위의 시점에 수행되며,
그 후에는 경로 핸들러(Controller)가 호출 됨.
/pipe/a/123 호출 -> "123" -> Pipe -> Controller
😶 내장 파이프
ValidationPipe
ParseIntPipe
ParseFloatPipe
ParseBoolPipe
ParseArrayPipe
ParseUUIDPipe
ParseEnumPipe
DefaultValuePipe
ParseFilePipe
😶 Binding pipes
import { Controller, Get, HttpStatus, Param, ParseIntPipe, Query} from "@nestjs/common";
/**
* https://docs.nestjs.com/pipes
*/
@Controller("/pipe")
export class PipeController {
//http://localhost:3000/pipe/a/123
@Get("/a/:id")
pipeA(@Param("id", ParseIntPipe) id: number ) {
console.log('id: ', id);
console.log('id: ', typeof id);
return "pipe test";
}
//http://localhost:3000/pipe/b/123
@Get("/b/:id")
pipeB(@Param("id", new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE })) id: number ) {
console.log('id: ', id);
console.log('id: ', typeof id);
return "pipe test";
}
//http://localhost:3000/pipe/c?id=123
@Get("/c")
pipeC(@Query("id", new ParseIntPipe({ errorHttpStatusCode: HttpStatus.NOT_ACCEPTABLE })) id: number ) {
console.log('id: ', id);
console.log('id: ', typeof id);
return "pipe test";
}
}
😶 Custom pipes
PipeTransform<T, R>
T : value
R: metadata
value: controller 실행 전, 매개변수
metadata: 매개변수의 메타데이터
Metadata의 속성
export interface ArgumentMetadata {
type: 'body' | 'query' | 'param' | 'custom';
metatype?: Type<unknown>;
data?: string;
}
import { ArgumentMetadata, Injectable, PipeTransform } from "@nestjs/common";
@Injectable()
export class ValidationPipe implements PipeTransform {
transform(value: any, metadata: ArgumentMetadata) {
return value;
}
}
😶 Object schema validation
: 위의 custom pipe 파일을 생성 후, zod와 같이 사용하면 값에대한 유효성 검사가 편리하게 사용이 가능하다.
zod 설치
$ npm install --save zod
1. ValidationCustomPipe 파일 생성.
import { ArgumentMetadata, Injectable, PipeTransform, BadRequestException } from "@nestjs/common";
import { ZodObject } from 'zod';
@Injectable()
export class ValidationCustomPipe implements PipeTransform {
constructor(private schema: ZodObject<any>) {}
transform(value: any, metadata: ArgumentMetadata) {
try {
this.schema.parse(value);
} catch(e) {
throw new BadRequestException("Validation failed");
}
return value;
}
}
2. zod 를 이용한 스키마 검증 파일 생성
import { z } from 'zod';
export const sampleDtoSchema = z
.object({
name: z.string(),
age: z.number(),
})
.required();
export type SampleDto = z.infer<typeof sampleDtoSchema>;
3. Controller에 아래와 같이 사용.
import { Body, Controller, Get, Post, HttpStatus, Param, ParseIntPipe, Query, UsePipes} from "@nestjs/common";
import { ValidationCustomPipe } from "src/common/pipes/validation.pipe";
import { sampleDtoSchema, SampleDto } from "./dto/sample.schema.dto";
/**
* https://docs.nestjs.com/pipes
*/
@Controller("/pipe")
export class PipeController {
@Post("/custom")
@UsePipes(new ValidationCustomPipe(sampleDtoSchema))
pipeCustom(@Body() dto: SampleDto) {
console.log("dto: ", dto);
return "pipe custom success";
}
https://www.npmjs.com/package/zod
zod
TypeScript-first schema declaration and validation library with static type inference. Latest version: 3.22.2, last published: 18 days ago. Start using zod in your project by running `npm i zod`. There are 4945 other projects in the npm registry using zod.
www.npmjs.com
😶 Class Validator
- TS만 사용가능하며, JS 사용하여 작성된 경우 사용 불가.
- npm Class Validator를 사용시, 유효성 검사를 편리하게 사용가능.
$ npm i --save class-validator class-transformer
import { ValidationPipe} from "@nestjs/common";
@Controller("/pipe")
export class PipeController {
@Post("/custom/2")
pipeCustom2(@Body(new ValidationPipe()) dto: SampleClassValidatorDto) {
console.log("dto: ", dto);
return "pipe custom success";
}
import { IsString, IsInt } from 'class-validator';
export class SampleClassValidatorDto {
@IsString()
name: string;
@IsInt()
age: number;
}
ValidationPipe()
- 해당 검증 파이프는 Nest에서 기본적으로 제공되므로 구축할 필요가 없음
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) {
if (!metatype || !this.toValidate(metatype)) {
return value;
}
const object = plainToInstance(metatype, value);
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);
}
}
전역 범위 파이프
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
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