View
Validation
movieData와 updateData의 데이터 타입에 따른 예외처리
1. movieData
DTO(데이터 전송 객체 , Data Transfer Object) 생성
dto 폴더 생성 및 create-movie.dto.ts 파일생성하여 dto 타입을 지정해준다.
// 클라이언트가 보낼수 있는 전송객체
export class CreateMovieDto {
readonly title: string;
readonly year: number;
readonly genres: string[];
}
유효성 검사 1 : ValidationPipe()
main.ts에 ValidationPipe추가app.useGlobalPipes(new ValidationPipe());
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());
await app.listen(3000);
}
bootstrap();
유효성 검사 2 : class-validator
- 설치
npm i class-validator class-transformer
- dto/create-movie.dto.ts에 class-validator 추가하여 유효성 검사.
import { IsNumber, IsString } from "class-validator";
export class CreateMovieDto {
@IsString()
readonly title: string;
@IsNumber()
readonly year: number;
@IsString({each : true}) // Validation 옵션
readonly genres: string\[\];
}
결과는 아래와 같으며, value의 type error를 잡아준다.
하지만, 보는 것처럼 잘못된 키가 들어왔을 경우에 대한 Validation을 하지 못한다.
{
"123" : "123"
}
//결과
{
"statusCode": 400,
"message": \[
"title must be a string",
"year must be a number conforming to the specified constraints",
"each value in genres must be a string"
\],
"error": "Bad Request"
}
{
"title" : "기생충",
"director": "봉준호",
"year" : "2019",
"genre" : "스릴러"
}
//결과
{
"statusCode": 400,
"message": \[
"year must be a number conforming to the specified constraints",
"each value in genres must be a string"
\],
"error": "Bad Request"
}
ValidationPipe의 옵션
1. whitelist : true로 설정하면 아무 decorator도 없는 어떠한 property의 object를 거릅니다.
If set to true validator will strip validated object of any properties that do not have any decorators.
Tip: if no other decorator is suitable for your property use @Allow decorator.
2. forbidNonWhitelisted : true로 설정하면 decorator가 없는 속성이 들어오면 예외처리됨.
If set to true, instead of stripping non-whitelisted properties validator will throw an error
3. transform : true로 설정하면 유저가 보낸 값을 controller에서 설정한 원하는 형식으로 바꿀 수 있음.
(ex url의 path parameter는 무조건 string으로 들어오므로 number로 변환하여 사용하여야 했으나, 이 옵션을 주게되면, 자동으로 number로 변환되어 들어옴. console.log(typeof id) )
main.ts
import { ValidationPipe } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { triggerAsyncId } from 'async\_hooks';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.useGlobalPipes(new ValidationPipe({
whitelist : true,
forbidNonWhitelisted : true,
transform: true
}));
await app.listen(3000);
}
bootstrap();
create_movie.dto.ts
import { IsNumber, IsString } from "class-validator";
export class CreateMovieDto {
@IsString()
readonly title: string;
@IsNumber()
readonly year: number;
@IsString({each : true})
readonly genres: string[];
}
movie/controller.ts
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('search')
search(@Query('year') searchingYear:string) {
return `we are searching for a movie made after ${searchingYear}`;
}
@Get(':id')
getOne(@Param('id') movieId: number): Movie{
return this.moviesService.getOne(movieId);
}
@Post()
create(@Body() movieData: CreateMovieDto){
console.log(movieData);
return this.moviesService.createOne(movieData);
}
@Delete(':id')
remove(@Param('id') movieId:number){
return this.moviesService.deleteOne(movieId);
}
@Patch(':id')
path(@Param('id') movieId:number, @Body() updateData) {
return this.moviesService.update(movieId, updateData);
}
}
movie/service.ts
import { Injectable, Delete, 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);
}
createOne(movieData: CreateMovieDto): boolean {
this.movies.push({
id: this.movies.length + 1,
...movieData
})
return true;
}
update(id:number, updateData) {
const movie = this.getOne(id);
this.deleteOne(id);
console.log(this.getAll())
this.movies.push({...movie, ...updateData});
}
}
2. updateData
DTO(데이터 전송 객체 , Data Transfer Object) 생성
방법 1. update-movie.dto.ts 파일생성하여 dto 타입을 지정해주는데, 부분만 수정할 수 있으니, ?의 옵션을 준다.
import { IsNumber, IsString } from "class-validator";
export class UpdateMovieDto {
@IsString()
readonly title?: string;
@IsNumber()
readonly year?: number;
@IsString({each : true})
readonly genres?: string[];
}
방법 2. mapped-types
: 타입을 변환시키고 사용할 수 있게하는 패키지
[https://www.npmjs.com/package/@nestjs/mapped-types]
PartialType()
설치
npm i --save @nestjs/mapped-types
1. Create-dto의 타입을 updare-dto의 타입으로 변환하기
import { PartialType } from "@nestjs/mapped-types";
import { CreateMovieDto } from "./create-movie.dto";
export class UpdateMovieDto extends PartialType(CreateMovieDto){
}
2. @IsOptional()
: 장르에 옵션주기
import { IsNumber, IsOptional, IsString } from "class-validator";
export class CreateMovieDto {
@IsString()
readonly title: string;
@IsNumber()
readonly year: number;
@IsOptional()
@IsString({each : true})
readonly genres: string[];
}
NestJS가 지원하는 class validaor는 정말 유용하다.
개발자가 일일이 에러를 잡아줄필요 없이,
실시간으로 NestJS가 서버를 보호해주고 있다.
class validaor의 많은 옵션들을 잘 활용해보도록 하자!
'NestJS' 카테고리의 다른 글
TIL | NestJS_URI_parameter_받아오기 (0) | 2021.10.17 |
---|---|
TIL | NestJS_REST_API_Module (0) | 2021.10.11 |
TIL | NestJS_REST_API_Service (0) | 2021.10.11 |
TIL | NestJS_REST_API_Controller (0) | 2021.10.11 |
TIL | NestJS_REST_API_Settings (0) | 2021.10.11 |