웹 어플리케이션으로 전송되는 데이터의 검증을 도와준다.
들어오는 요청을 자동으로 검증하기 위해 nest는 즉시 사용할 수 있는 여러 파이프를 제공한다.
ValidationPipe
강력한 클래스 유효성 검사기 패키지와 선언적 유효성 검사 데코레이터를 사용한다. ValidationPipe는 들어오는 모든 클라이언트 페이로드에 대해 유효성 검사 규칙을 적용하는 편리한 접근 방식을 제공한다.
자동 검증
어플리케이션 수준에서 ValidationPipe를 바인딩
모든 엔드포인트가 잘못된 데이터를 수신하지 못하도록 보호한다.
whitelist
true를 설정하면 유효성 검사기는 class-validator의 유효성 검사 데코레이터를 적어도 하나라도 사용하지 않은 모든 속성 객체를 제거한다.
forbidNonWhitelisted
true로 설정하면 화이트리스트에 없는 속성을 제거하는 대신 유효성 검사기가 throw한다.
transform(자동 형변환)
네트워크를 통해 들어오는 payload는 일반 JavaScript 객체다. ValidationPipe는 payload를 DTO 클래스에 따라 유형이 지정된 객체로 자동 변환할 수 있다.
import { IsNumber, IsString } from 'class-validator';
export class CreateMovieDto {
// 사용자가 보내야하는 정보 (읽기전용)
@IsString()
readonly title: string;
@IsNumber()
readonly year: number;
@IsString({ each: true })
readonly genres: string[];
}
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, // true로 설정하면 아무 decorator도 없는 어떠한 property의 object를 거른다.
forbidNonWhitelisted: true, // 이상한걸 보내면 요청 자체를 막을 수 있음
transform: true, // 요청온 데이터를 원하는 타입으로 변환해줌
}),
);
await app.listen(3000);
}
bootstrap();
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
Put,
Query,
} from '@nestjs/common';
import { CreateMovieDto } from './dto/create-movie.dto';
import { Movie } from './entities/movie.entity';
import { MoviesService } from './movies.service';
@Controller('movies')
export class MoviesController {
constructor(private readonly moviesService: MoviesService) {}
@Get()
getAll(): Movie[] {
return this.moviesService.getAll();
}
@Get('/:id')
getOne(@Param('id') movieId: number): Movie {
console.log(typeof movieId);
return this.moviesService.getOne(movieId);
}
@Post()
create(@Body() movieData: CreateMovieDto) {
return this.moviesService.create(movieData);
}
@Delete('/:id')
remove(@Param('id') movieId: number) {
return this.moviesService.deleteOne(movieId);
}
@Patch('/:id')
patch(@Param('id') movieId: number, @Body() updateData) {
return this.moviesService.update(movieId, updateData);
}
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateMovieDto } from './dto/create-movie.dto';
import { Movie } from './entities/movie.entity';
@Injectable()
export class MoviesService {
private movies: Movie[] = [];
getAll(): Movie[] {
return this.movies;
}
getOne(id: number): Movie {
const movie = this.movies.find((movie) => movie.id === +id);
if (!movie) {
throw new NotFoundException(`Movie with ID ${id} not found.`);
}
return movie;
}
deleteOne(id: number) {
this.getOne(id);
this.movies = this.movies.filter((movie) => movie.id !== +id);
}
create(movieData: CreateMovieDto) {
this.movies.push({
id: this.movies.length + 1,
...movieData,
});
}
update(id: number, updateData) {
const movie = this.getOne(id);
this.deleteOne(id);
this.movies.push({ ...movie, ...updateData });
}
}