nestjs에서 사용자 정의 validate 구현하기
class-validator에서는 많은 validation 조건을 제공하여 줍니다. 하지만 사용자 정의 옵션이 필요할 때가 있는데, 이때 설정이 생각보다 복잡하네요.
ValidatorConstraintInterface 구현 하기
class-validator는 ValidatorConstraintInterface interface를 구현해서 사용자 정의 validation 처리를 합니다.
아래는 구현된 예제 입니다.
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
@ValidatorConstraint({ name: 'customText', async: false })
export class CustomTextLength implements ValidatorConstraintInterface {
validate(text: string, args: ValidationArguments) {
return text.length > 1 && text.length < 10; // for async validations you must return a Promise<boolean> here
}
defaultMessage(args: ValidationArguments) {
// here you can provide default error message if validation failed
return 'Text ($value) is too short or too long!';
}
}
사용 예제
아래는 Post 클래스의 사용자 정의 validate를 사용하는 예제입니다.
import { Validate } from 'class-validator';
import { CustomTextLength } from './CustomTextLength';
export class Post {
@Validate(CustomTextLength, {
message: 'Title is too short or long!',
})
title: string;
}
nestjs에 적용 하기
위와 같이 설정 후
@Injectable
을 사용하면 오류를 확인 할 수 있습니다. How to inject service to validator constraint interface in nestjs using class-validator?를 참고 하면 아래와 같은 컨테이너 처리를 추가 해야 합니다.
// Custom Validate
import {ValidatorConstraint, ValidatorConstraintInterface} from 'class-validator';
import {UsersService} from './user.service';
import {Injectable} from '@nestjs/common';
@ValidatorConstraint({ name: 'isUserAlreadyExist', async: true })
@Injectable() // this is needed in order to the class be injected into the module
export class IsUserAlreadyExist implements ValidatorConstraintInterface {
constructor(protected readonly usersService: UsersService) {}
async validate(text: string) {
const user = await this.usersService.findOne({
email: text
});
return !user;
}
}
// UserModule
import {Module} from '@nestjs/common';
import { UsersController } from './user.controller';
import { UsersService } from './user.service';
import { IsUserAlreadyExist } from './user.validator';
@Module({
controllers: [UsersController],
providers: [IsUserAlreadyExist, UsersService],
imports: [],
exports: []
})
export class UserModule {
}
// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
useContainer(app.select(AppModule), { fallbackOnErrors: true });
...}
위와 같이 설정하면 inject이 정상적으로 처리 되는 것을 확인 할 수 있습니다.
약간 복잡해 보이는 설정인데, 한줄씩 코드로 보면 어렵지 않습니다.