🔍 Intro: NestJS는 왜 DTO 유효성 검사가 중요한가?
NestJS는 객체지형, 함수형, 함수형 반응형 프레임워크를 결합한 의연성 주입 기반의 Node.js 백엔드 프레임워크입니다. 이 프레임워크는 타입 기반 개발을 지향하고 있으며, API 개발 시 입력값 검사과 타입 변환을 중요한 기본 기능으로 포함하고 있습니다.
하지만 TypeScript의 타입은 컴파일 타임에만 존재하고, 런타임에는 사라지기 때문에 다음과 같은 문제가 생길 수 있습니다:
- ✅
"런턴임에 들어온 요청의 body가 지정한 DTO 타입과 일치하는가?"
- ❌
"타입스크립트가 타입을 강제하지 않으므로, 유효성 검사가 없다면 잘못된 값도 통과합니다."
이를 해결해주는 것이
class-validator
와 class-transformer
입니다.class-validator와 class-transformer란?
| 패키지 | 설명 |
| --- | --- |
|
class-validator
| 데코레이터 기반의 유효성 검사. @IsString()
, @IsEmail()
등 |
| class-transformer
| plain object ↔ class instance 변환 (예: JSON → DTO 객체) |NestJS에서는 이 두 패키지를 활용해 런턴임에서도 안전한 DTO 기본 검사를 할 수 있게 지원합니다.
NestJS에서는
ValidationPipe
를 통해 그룹으로 연결합니다:// main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
transform: true, // class-transformer 사용
whitelist: true, // DTO에 정의된 값만 허용
forbidNonWhitelisted: true, // 정의되지 않은 속성은 오류
}),
);
await app.listen(3000);
}
사용 예시: 유저 등록 DTO
// dto/create-user.dto.ts
import { IsString, IsEmail, MinLength } from 'class-validator';
export class CreateUserDto {
@IsEmail()
email: string;
@IsString()
@MinLength(6)
password: string;
@IsString()
nickname: string;
}
함수에서 적용:
@Post('signup')
createUser(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
class-transformer와 타입 변환
import { Type } from 'class-transformer';
import { IsDate } from 'class-validator';
export class EventDto {
@Type(() => Date)
@IsDate()
date: Date;
}
해설: 만약
@Type(() => Date)
가 없으면 @IsDate()
는 무작위로 실패합니다. (date
는 string으로 들어오기 때문)💡 ValidationPipe 옵션 정보
| 옵션 | 설명 |
| --- | --- |
|
transform
| JSON → class instance 변환 (타입 변환 포함) |
| whitelist
| DTO에 없는 속성은 제거 |
| forbidNonWhitelisted
| 정의되지 않은 속성이 오면 오류 |
| skipMissingProperties
| DTO에 없는 값은 검사하지 않음 |
| enableDebugMessages
| 디버그 메시지 출력 (NestJS 9+) |Before vs After 비교
사용 전: 유효성 검사 모두 수동 구현
@Post('signup')
createUser(@Body() body: any) {
const { email, password, nickname } = body;
if (typeof email !== 'string' || !email.includes('@')) {
throw new BadRequestException('유효한 이메일을 입력해주세요.');
}
if (typeof password !== 'string' || password.length < 6) {
throw new BadRequestException('비밀번호는 최소 6자 이상이어야 합니다.');
}
return this.userService.create({ email, password, nickname });
}
사용 후: 자동 유효성 검사 + 타입 변환
@Post('signup')
createUser(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
- DTO에 데코레이터 검사 조건을 포함
- 자동으로 타입 확인 + 유효성 검사
🚨 자주 발생하는 실수
transform: true
설정 맞는가? 값 타입 변환이 안됨@Type(() => Number)
바로 적용해야 타입이 변환됨whitelist: true
가 없으면 잘못된 필드도 통과
마무리하며
class-validator
와 class-transformer
는 NestJS에서 API의 신력성을 보장하는 내용으로 너무 중요한 도구입니다. 다음과 같은 다양한 이유로 사용해야 합니다.- 유효성 검사 자동화
- 타입 안전성 + 자동 변환
- Swagger, 문서, 코드 테스트에서 DTO 재사용 가능
- 보안 강화 (불필요 필드 차단)