- 데이터 변환 (Transformation): 데이터를 다른 형식으로 변환.
- 데이터 검증 (Validation): 요청 데이터가 유효한지 확인.
Pipe
는컨트롤러 핸들러
로 들어가기 전에 데이터를 처리한다.
NestJS는 기본적으로 제공하는 Pipe
가 있다.
Pipe 이름 | 설명 |
---|---|
ValidationPipe | 요청 데이터를 검증 (e.g., DTO와 class-validator 사용) |
ParseIntPipe | 요청 데이터를 정수로 변환 |
ParseBoolPipe | 요청 데이터를 부울 값으로 변환 |
ParseArrayPipe | 요청 데이터를 배열로 변환 |
ParseUUIDPipe | 요청 데이터를 UUID 형식으로 검증 |
DefaultValuePipe | 값이 없을 경우 기본값을 제공 |
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(
new ValidationPipe({
whitelist: true, // 정의하지 않은 값들은 전부 전달이 안되게 함, dto 에 존재하는값과 존재하지않는 값 구분이 가능
forbidNonWhitelisted: true, // whitelist에서 걸리면 에러까지 return
}),
);
await app.listen(process.env.PORT ?? 3000);
}
bootstrap();
main.ts
에useGlobalPipes
를 적용해서 전역으로pipe
를 사용할 수 있다.
import {
ArgumentMetadata,
BadRequestException,
Inject,
Injectable,
PipeTransform,
} from '@nestjs/common';
@Injectable()
export class MovieTitleValidationPipe implements PipeTransform<string, string> {
transform(value: string, metadata: ArgumentMetadata): string {
if (!value) {
return value;
}
// 만약에 글자 길이가 1보다 작거나 같으면 에러 던지기!
if (value.length <= 1) {
throw new BadRequestException('영화의 제목은 3자 이상 작성해주세요!');
}
return value;
}
}
Custom pipe
를 만들기 위해서는PipeTransform
를 implements 해야한다.- 입력과 반환 타입의 제네릭을 명시한다.
value: string
은 요청 데이터의 값이다.metadata: ArgumentMetadata
는 요청 데이터에 대한메타데이터
인데
type:
데이터의 타입 (body, query, param, 등).
metatype:
데이터의 클래스 또는 원시 타입 (e.g., String, Number, CreateMovieDto).
data:
매개변수 이름 또는 키 이름. 이 있다.- 로직은 글자의 길이가 1보다 작거나 같으면 에러를 던지고 아니면
value
를 리턴해준다.
@Get()
getMovies(@Query('title', MovieTitleValidationPipe) title?: string) {
return this.movieService.findAll(title);
}
- 위에서 만든 Custom pipe를 파라미터에 적용 시켜서 검증할 수 있다!
@Controller('movie')
@UsePipes(MovieTitleValidationPipe)
@UseInterceptors(ClassSerializerInterceptor) // class-transformer를 movie controller에 적용을 하기 위한 코드
export class MovieController {
constructor(private readonly movieService: MovieService) {}
@Get()
getMovies(@Query('title', MovieTitleValidationPipe) title?: string) {
return this.movieService.findAll(title);
}
@Get(':id')
getMovie(@Param('id', ParseIntPipe) id: number) {
console.log(test);
return this.movieService.findOne(id);
}
@Controller
annotation에 적용하면 모든 핸들러에pipe
가 적용된다.
@Patch(':id')
@UsePipes(MovieTitleValidationPipe)
patchMovie(
@Param('id', ParseIntPipe) id: string,
@Body() body: UpdateMovieDto,
) {
return this.movieService.update(+id, body);
}
- 각 라우터에 annotation을 적용할 수 도 있다.