DTOs and Validation 1

emily,h·2022년 7월 16일
0

DTO

  • Data Transfer Object의 약자로서, 데이터를 오브젝트로 변환하는 객체
  • 어떠한 값이 어떤 타입을 가지고 이 값이 필수인지 옵션인지 정의하기위한 파일
  • nestjs가 들어오는 쿼리에 대해 유효성을 검사할 수 있게 해준다.

Validation

  • 웹 어플리케이션으로 전송되는 데이터의 검증을 도와준다.
    들어오는 요청을 자동으로 검증하기 위해 nest는 즉시 사용할 수 있는 여러 파이프를 제공한다.

  • ValidationPipe
    강력한 클래스 유효성 검사기 패키지와 선언적 유효성 검사 데코레이터를 사용한다. ValidationPipe는 들어오는 모든 클라이언트 페이로드에 대해 유효성 검사 규칙을 적용하는 편리한 접근 방식을 제공한다.

  • 자동 검증
    어플리케이션 수준에서 ValidationPipe를 바인딩
    모든 엔드포인트가 잘못된 데이터를 수신하지 못하도록 보호한다.

  • whitelist
    true를 설정하면 유효성 검사기는 class-validator의 유효성 검사 데코레이터를 적어도 하나라도 사용하지 않은 모든 속성 객체를 제거한다.

  • forbidNonWhitelisted
    true로 설정하면 화이트리스트에 없는 속성을 제거하는 대신 유효성 검사기가 throw한다.

  • transform(자동 형변환)
    네트워크를 통해 들어오는 payload는 일반 JavaScript 객체다. ValidationPipe는 payload를 DTO 클래스에 따라 유형이 지정된 객체로 자동 변환할 수 있다.

create-movie.dto

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

export class CreateMovieDto {
  // 사용자가 보내야하는 정보 (읽기전용)

  @IsString()
  readonly title: string;

  @IsNumber()
  readonly year: number;

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

main

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

controller

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

movies.service

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

0개의 댓글