정보 전달의 포스팅 보단 학습 메모 목적의 포스팅 입니다. 😢
부족한 설명과 내용에 대해 미리 양해 부탁드립니다.
DTO란?
- 데이터 전송 객체를 의미, 계층 간 데이터 교환을 위해 사용하는 객체.
- controller와 service의 create함수의 타입에 DTO를 지정
DTO 작성, Validation 체크 (npm i class-valitator
)
// create-movie.dto.ts
import { IsNumber, IsOptional, IsString } from 'class-validator';
// DTO란?
// 데이터 전송 객체를 의미, 계층 간 데이터 교환을 위해 사용하는 객체.
// controller와 service의 create함수의 타입에 DTO를 지정
export class CreateMovieDto {
@IsString()
readonly title: string;
@IsNumber()
readonly year: number;
// each 옵션은 모든 요소를 하나씩 검사하겠다는 뜻
@IsOptional()
@IsString({ each: true })
readonly genres: string[];
}
// update-movie.dto.ts
import { IsNumber, IsString } from 'class-validator';
import { PartialType } from '@nestjs/mapped-types';
import { CreateMovieDto } from './create-movie.dto';
// npm i @nestjs/mapped-types
// create의 DTO와 update의 DTO는 required의 여부에만 차이가 있다. (create는 필수 옵션들이지만 update는 일부만 수정도 가능하기 때문.)
// PartialType의 인자 안에 CreateMovieDto를 넣어주게 된다면 옵셔널하게 수정이 가능하다.
export class UpdateMovieDto extends PartialType(CreateMovieDto) {}
Controller 코드와 Service 코드
// movies.controller.ts
import { Controller, Delete, Get, Param, Post } from '@nestjs/common';
import { Body, Patch } from '@nestjs/common/decorators';
import { CreateMovieDto } from './dto/create-movie.dto';
import { UpdateMovieDto } from './dto/update-movie.dto';
import { Movie } from './entities/movie.entity';
import { MoviesService } from './movies.service';
@Controller('movies')
export class MoviesController {
constructor(private readonly moviesService: MoviesService) {}
// NestJS는 Express 위에서 돌아가기 때문에 컨트롤러에서 Req, Res객체가 필요하면 사용할 수 있음
// getAll(@Req() req, @Res() res): Movie[] { res.json() ... 와 같이 사용 가능
// 하지만 Express 객체를 직접적으로 사용하는 건 좋은 방법이 아님 (두 개(express, fastify)의 프레임워크랑 작동하기 때문)
@Get()
getAll(): Movie[] {
return this.moviesService.getAll();
}
// 주의 해야 할 점
// :id 와 같은 동적 라우팅을 가진 getOne함수 아래에 같은 Get 메소드인 search함수가 있다면 search의 값이 동적 라우팅의 값이 돼버린다.
@Get(':id')
getOne(@Param('id') movieId: number): Movie {
return this.moviesService.getOne(movieId);
}
@Post()
cerate(@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: UpdateMovieDto) {
return this.moviesService.update(movieId, updateData);
}
}
// movies.service.ts
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateMovieDto } from './dto/create-movie.dto';
import { UpdateMovieDto } from './dto/update-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} `);
}
return movie;
}
deleteOne(id: number): boolean {
this.getOne(id);
this.movies = this.movies.filter((movie) => movie.id !== id);
return true;
}
create(movieData: CreateMovieDto) {
this.movies.push({
id: this.movies.length + 1,
...movieData,
});
}
update(id: number, updateData: UpdateMovieDto) {
const movie = this.getOne(id);
this.deleteOne(id);
this.movies.push({ ...movie, ...updateData });
}
}
파일 모듈화
// movies.module.ts
import { Module } from '@nestjs/common';
import { MoviesController } from './movies.controller';
import { MoviesService } from './movies.service';
@Module({
// 기능 별 모듈화 시키기
// movies의 controller와 service를 movies.module로 묶은 후 app.module에 import 항목 안에 넣어준다.
controllers: [MoviesController],
providers: [MoviesService],
})
export class MoviesModule {}
import { Module } from '@nestjs/common';
import { MoviesModule } from './movies/movies.module';
import { AppController } from './app.controller';
@Module({
imports: [MoviesModule],
controllers: [AppController],
providers: [],
})
export class AppModule {}
파일 구조
│ app.controller.ts
│ app.module.ts
│ main.ts
│
└─movies
│ movies.controller.ts
│ movies.module.ts
│ movies.service.ts
│
├─dto
│ create-movie.dto.ts
│ update-movie.dto.ts
│
└─entities
movie.entity.ts
위와 같은 코드를 통해 DB를 연결하지 않은 서버에서만 동작하는 API를 만들어 보았다.(간단하게 테스트 하는 용도)
이번 Nest.js 를 통해 REST API를 구축하고, DB와의 연결, 유효성 체크 등 백엔드의 지식을 함양할 수 있게 되는 계기가 됐으면 좋겠다.
현재까지 공부의 핵심
- Nest.js 는 Express의 단점을 보완해주는 좋은 프레임워크
- 여러 데코레이터들을 통해 CRUD를 작성할 수 있고, ValidationPipe를 통해 보다 쉽게 유효성을 검사할 수 있다. (https://www.npmjs.com/package/class-validator class-validation공식 문서)
- ValidationPipe의 whitelist, forbidNonWhitelisted, transform 옵션들과 DTO를 통해 클라이언트와 서버간의 데이터 전송방식 에서의 편리성을 가진다.
- 모듈화를 통해 보다 좋은 파일구조를 가질 수 있다.
'Nest.js' 카테고리의 다른 글
[Nest.js] Nest.js + PostgreSQL + typeORM CRUD 구현하기 1 (1) | 2023.01.26 |
---|---|
[Nest.js] Providers란? (0) | 2023.01.25 |
[Nest.js] jest를 이용한 테스트 코드 작성 (0) | 2023.01.13 |
[Nest.js] Nest.js CRUD 실습 (REST API) (0) | 2023.01.11 |
[Nest.js] Nest 설치 (0) | 2023.01.11 |