Class Validator 란?
예시
글로벌로 적용하기 위해 필요한 설정
main.ts 에 다음 코드를 반드시 설정해주어야 한다.
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
import { ValidationPipe } from "@nestjs/common";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// 앱 전반에서 Validation 을 사용 가능
app.useGlobalPipes(new ValidationPipe());
await app.listen(3000);
}
bootstrap();
DTO 작성
@IsString(), @IsNotEmpty() 등의 validator 를 통해 제약조건을 건다.
@IsString(): 문자열만 가능
@IsNotEmpty(): 반드시 입력해야 하는 필수 값
import { IsNotEmpty, IsString } from "class-validator";
export class CreatePostDto {
@IsString()
@IsNotEmpty()
title: string;
@IsString()
content: string;
}
컨트롤러
@Body 부분을 작성한 Dto 타입으로 정의해주면, DTO 는 위에
@Post()
@UseGuards(AccessTokenGuard)
postPosts(@User('id') id: number, @Body() body: CreatePostDto) {
return this.postsService.createPost(id, body);
}
검증 후 메세지 변경하기
- 데코레이터의 인자에
{} 로 옵션을 넣어줄 수 있다.
message 를 추가하면, 해당 메세지로 검증 결과를 받아볼 수 있다.
import { IsNotEmpty, IsString } from "class-validator";
export class CreatePostDto {
@IsString({
message: "제목은 문자로 입력해주어야 합니다.",
})
@IsNotEmpty({
message: "제목은 반드시 입력해야 합니다.",
})
title: string;
@IsString()
content: string;
}
ValidationPipe 은 어떻게 구현되어 있을까?
- Global 하게 적용되어 모든
class-validator 가 이 로직에 맞춰 동작하게 만들어준다.
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;
}
// 네이티브 JS 타입인 경우 검사를 하지 않음
private toValidate(metatype: Function): boolean {
const types: Function[] = [String, Boolean, Number, Array, Object];
return !types.includes(metatype);
}
}
기타 옵션들
export interface ValidationOptions {
/**
* 배열에서 각각의 아이템들이 검증되어야 하는 경우
*/
each?: boolean;
/**
* 검증 실패 시 보여줄 메세지, `ValidationArguments` 를 통해 함수로 작성도 가능하다.
*/
message?: string | ((validationArguments: ValidationArguments) => string);
/**
* 이 검증에 사용될 검증 그룹 (아마 검증 그룹이라는 걸 만들어서 여러개의 검증을 묶을 수 있는듯하다.)
*/
groups?: string[];
/**
* 검증 그룹 상관없이 항상 검증을 하는가?
*/
always?: boolean;
context?: any;
}