728x90
반응형

 

updateData랑 movieData한테 타입을 부여하기 위해서 우리는 DTO(Data Transfer Object, 데이터 전송 객체)를 만들어야한다. 먼저 create-movie.dto.ts 파일을 만들자.

 

 

create-movie.dto.ts

export class CreateMovieDto {
    readonly title: string;
    readonly year: number;
    readonly genres: string[];
}

 

 

그 다음 Controller 부분과 Service 부분에 타입을 추가해주자. (movieData)

 

Controller

    @Post()
    create(@Body() movieData : CreateMovieDto) {
        return this.moviesService.create(movieData);
    }

 

Service

    create(movieData:CreateMovieDto) {
        this.movies.push({
            id: this.movies.length + 1,
            ...movieData
        })
        return true;
    }

 

이렇게 해두면 아래와 같이 movieData. 만 입력해도 클래스가 가진 속성들이 자동으로 나와서 코딩하기에도 편리하다.

또한 타입에 대한 유효성을 검사할 수도 있다.

 

클래스의 유효성 검사를 위해 main.ts에 다음과같이 pipe를 만들어주겠다.

 

main.ts

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();

 

 

또한 아래 명령어를 입력해서  npm 모듈을 설치하자.

$npm i class-validator class-transformer

 

그다음 아까 만들어두었던 dto파일에 다음과같이 데코레이터를 추가하자.

 

create-movie.dto.ts

import {IsString, IsNumber} from 'class-validator'

export class CreateMovieDto {
    @IsString()
    readonly title: string;

    @IsNumber()
    readonly year: number;
    
    @IsString({each:true})
    readonly genres: string[];
}

 

 

 

그 다음 postman에서 다음과 같이 POST 메소드로 {hacked: "by me"} 라는  body를 요청해보면 이런 결과창이 뜬다.

 

ValidationPipe 와 CreateMovieDto를 사용하고 있기 때문에 DTO의 타입을 실시간으로 확인할 수 있는 것이다.

 

ValidationPipe의 옵션 중 유용한 옵션인 whitelist라는 것이 있는데,

true로 설정하면 아무 Decoreator도 없는 어떠한 property의 object를 거룰 수 있다.

 

또한 보안을 위해 forbidNonWhitelisted 라는 옵션도 있다. 

이는 정의를 하지 않은 데이터가 error메세지에 뜨게끔 도와준다

 

transform라는 옵션은

보통 데이터를 body로 받을 때 string으로 받아서 정수형은 parseInt를 써야 했지만,

그럴 필요 없이 바로 원하는 자료형으로 바꿔주는 기능을 한다.

 

 

여기까지 추가를 해보면

 

 

main.ts

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, 
      forbidNonWhitelisted : true,
      transform : true
    })
  )
  await app.listen(3000);
}
bootstrap();

 

 

이렇게 되고, 추가했었던 parseInt를 바꿔주면 된다.

 

movies.controller.ts

import { Controller, Get, Param, Post, Delete, Patch, Body, 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){
        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)
    }
}

 

 

movies.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { NotFoundError } from 'rxjs';
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(" ID가 존재하지 않습니다. ")
        }

        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
        })
        return true;
    }

    update(id: number, updateData) {
        const movie = this.getOne(id);
        this.deleteOne(id)
        this.movies.push({ ...movie, ...updateData})
    }

}

 

728x90
반응형

+ Recent posts