NestJS로 API 만들기

https://nomadcoders.co/nestjs-fundamentals


노마드코더 강의를 참고하고 있습니다.

 


문제점

  • src/movies/entities/movies.entity.ts

Entity 파일은 데이터베이스의 테이블과 상호 작용하기 위해 데이터 모델을 정의하고 캡슐화한다.

하지만 정의된 값(id, title, year, geners)이 아닌 다른 값(hacked)을 전송해도 HTTP 요청을 성공적으로 처리한다. (Status 200)

이와 같은 문제를 해결하기 위해서는 DTO를 사용한다.

export class Movie {
  id: number;
  title: string;
  year: number;
  genres: string[];
}

 


DTO란

데이터 전송 객체(DTO, Data Transfer Object)는 클라이언트와 서버 간 데이터 교환을 위한 객체로 사용된다.

  • 클라이언트에서 서버로 데이터를 전송할 때 정확한 데이터 형식을 정의할 수 있어 잘못된 데이터 전송을 방지할 수 있다.
  • 클라이언트가 전송하는 데이터는 종종 서버에서 사용되는 형식과 다를 수 있는데 DTO를 사용해 서버에서 필요한 형식으로 변환할 수 있다.
  • 필요한 데이터만 전송받아 불필요한 정보 노출을 방지해 보안을 강화할 수 있다.

 

1. create DTO 만들기

  • src/movies/dto/create-movies.dto.ts
  1. dto 폴더를 만들고, create-movies.dto.ts 파일을 만든다.
  2. class-validator, class-transformer 패키지를 설치한다. 이 패키지들은 데이터 유효성 검사와 객체 변환을 쉽게 수행할 수 있도록 도와준다. (@IsString(), @IsNumber(), @IsOptional(), @MinLength() 등..)
npm install class-validator class-transformer
import { IsString, IsNumber, IsOptional } from "class-validator";

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

  @IsNumber()
  readonly year: number;

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

 

2. update DTO 만들기

  • src/movies/dto/update-movies.dto.ts
  1. dto 폴더에 update-movies.dto.ts 파일을 만든다.
  2. PartialType()은 DTO 클래스의 모든 필드를 선택적으로 만들어주는 역할을 하고, 부분 업데이트를 수행할 때 사용한다. CreateMoviesDto의 모든 필드를 선택적으로 가지게 된다.
  3. 업데이트는 모든 필드의 수정이 필요 없기 때문에 ? 물음표를 사용해 선택 속성임을 나타낸다.
import { IsString, IsNumber } from 'class-validator';
import { PartialType } from '@nestjs/mapped-types';
import { CreateMoviesDto } from './create-movies.dto';

export class UpdateMoviesDto extends PartialType(CreateMoviesDto) {
  @IsString()
  readonly title?: string;

  @IsNumber()
  readonly year?: number;

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

 

3. DTO import 하기

  • src/movies/movies.service.ts
  1. CreateMoviesDto, UpdateMoviesDto를 import 한다.
  2. create 함수에 movieData 데이터 타입을 CreateMoviesDto로 명시한다.
  3. update 함수에 updateData 데이터 타입을 UpdateMoviesDto로 명시한다.
import { CreateMoviesDto } from './dto/create-movies.dto';
import { UpdateMoviesDto } from './dto/update-movies.dto';
...

@Injectable()
export class MoviesService {
  private movies: Movie[] = [];

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

  update(id: number, updateData: UpdateMoviesDto) {
    const movie = this.getOne(id);

    this.deleteOne(id);
    this.movies.push({ ...movie, ...updateData });
  }
  
  ...
}

 

  • src/movies/movies.controller.ts
  1. CreateMoviesDto, UpdateMoviesDto를 import 한다.
  2. POST 요청을 보낼 때 데이터 타입을 CreateMoviesDto로 명시한다.
  3. PATCH 요청을 보낼 때 데이터 타입을 UpdateMoviesDto로 명시한다.
import { CreateMoviesDto } from './dto/create-movies.dto';
import { UpdateMoviesDto } from './dto/update-movies.dto';
...

@Controller('movies') // Entry Point(URL)
export class MoviesController {
  constructor(private readonly moviesService: MoviesService) {}

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

  @Patch('/:id')
  patch(@Param('id') movieId: number, @Body() updateData: UpdateMoviesDto) {
    return this.moviesService.update(movieId, updateData);
  }
  
  ...
}

 

4. 결과 확인하기

DTO에 정의되지 않은 속성 또는 잘못된 타입을 POST 하면 에러 메세지가 나타난다.

 

DTO에 정의되지 않은 속성 또는 잘못된 타입을 PATCH 하면 에러 메세지가 나타난다.

+ Recent posts