ValidationPipe 제대로 이해하기
ValidationPipe 제대로 이해하기
시작하기에 앞서
난 아직 ValidationPipe에서 transform 옵션만 켜둔 상태였기 때문에
보안 관련 옵션인 whitelist와 forbidNonWhitelisted를 적용하려 한다!
1. ValidationPipe 전역 설정하기
Nest.js에서는 main.ts
에서 ValidationPipe
를 전역으로 적용할 수 있다.
이렇게 하면 모든 엔드포인트에 자동으로 유효성 검증이 걸려서 컨트롤러마다 따로 처리할 필요가 없어진다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // DTO에 없는 속성 제거
forbidNonWhitelisted: true, // 허용되지 않은 속성 있으면 에러 발생
transform: true, // 요청 값을 DTO 타입에 맞게 변환
}),
);
await app.listen(3000);
}
bootstrap();
2. 주요 옵션 설명
transform: true
- 요청으로 들어온 값을 DTO에 정의된 타입으로 자동 변환
- 예:
"20"
(string) →20
(number)
whitelist: true
- DTO에 정의되지 않은 속성은 자동으로 제거
- 불필요한 데이터가 들어와도 무시됨
forbidNonWhitelisted: true
- DTO에 없는 속성이 들어오면 에러를 발생
whitelist
보다 더 엄격한 옵션
disableErrorMessages: true
(선택)
- 에러 메시지 비활성화
- 프로덕션 환경에서 민감한 정보 노출 방지를 위해 사용
3. DTO와 Validation 예시
예시 DTO 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { IsString, IsInt, MinLength, Min } from 'class-validator';
export class CreateRestaurantDto {
@IsString()
@MinLength(2)
name: string;
@IsString()
address: string;
@IsInt()
@Min(1)
seatCount: number;
}
컨트롤러에 적용
1
2
3
4
5
6
7
8
9
10
import { Body, Controller, Post } from '@nestjs/common';
import { CreateRestaurantDto } from './restaurant.dto';
@Controller('restaurants')
export class RestaurantController {
@Post()
create(@Body() data: CreateRestaurantDto) {
return data;
}
}
잘못된 요청 예시
1
2
3
4
5
6
{
"name": "A",
"address": "서울",
"seatCount": "0",
"extra": true
}
응답 (400 에러)
1
2
3
4
5
6
7
8
9
{
"statusCode": 400,
"message": [
"name must be longer than or equal to 2 characters",
"seatCount must not be less than 1",
"property extra should not exist"
],
"error": "Bad Request"
}
transform: true → seatCount가 문자열로 들어와도 숫자로 변환
whitelist: true → DTO에 없는 필드는 제거 대상이지만, forbidNonWhitelisted가 true이면 에러 발생
forbidNonWhitelisted: true → extra 필드 때문에 에러 발생
class-validator → name과 seatCount는 각각 @MinLength(), @Min 유효성 검사에 의해 에러 발생
결론
ValidationPipe는 전역으로 적용해두면 가장 안전하다.
커스텀 검증기(validator)를 활용하면 서비스에 맞는 맞춤형 유효성 검사도 가능하다.
컨트롤러와 서비스는 핵심 비즈니스 로직에만 집중할 수 있게 된다.
This post is licensed under CC BY 4.0 by the author.