nomadcoder를 통해서 영화 API를 만들어보면서 API를 NestJS에 대해 학습할 계획.
SetUp
nest-cli를 통해 모듈과 서비스를 간단하게 생성할 수 있다.
nest g co
위 커맨드를 입력하면 만들 컨트롤러의 이름을 정하라고 나온다. 나는 movies라는 이름으로 정했다.
이렇게 되면 movies라는 폴더가 생길 것이고 안에 컨트롤러 파일이 생성되어 있을 것이다.
또한 앱 모듈 파일에 컨트롤러가 들어가져 있는 것을 볼 수 있다.
그리고 Rest API를 쉽게 테스트할 수 있게 도와주는 insomnia 프로그램을 사용한다.
Movies Controller
간단한 Movie의 CRUD를 작성해보자.
먼저 모든 영화를 가져오기 위한 getAll
@Get()
getAll() {
return "This will return all movies"
}
다음은 영화 하나를 가져오기 위한 getOne
@Get("/:id")
getOne(@Param('id') id: string) {
return `This will return one movie with id: ${id}`
}
Get데코레이터와 Param데코레이터에는 id로 동일해야하며 뒤의 타입은 달라도 된다.
@Get("/:id")
getOne(@Param('id') movieId: string) {
return `This will return one movie with id: ${movieId}`
}
다음은 영화를 추가하기 위한 creat이다.
@Post()
create() {
return "This will create movie"
}
다음은 영화를 삭제하기 위한 remove이다.
@Delete("/:id")
remove(@Param("id") id: string) {
return `This will delete one movie with id: ${id}`
}
이제 수정을 해야하는데 여기서 HTTP Request 메소드 데코레이터를 Put이나 Patch를 쓸 수 있다.
Put은 모든 정보를 수정할 때 사용하며, Patch는 정보 일부분을 수정할 때 사용한다.
@Patch("/:id")
patch(@Param("id") id: string) {
return `This will update one movie with id: ${id}`
}
Movies Service
서비스는 로직을 관리하는 역할이라고 보면 된다.
마찬가지로 nest-cli를 통해 서비스 파일을 쉽게 생성할 수 있다.
nest g s
커맨드를 실행하면 이름을 정하는게 나올 것이고 이름을 정해주면 컨트롤러와 마찬가지로 앱 모듈 파일에 알아서 입력된다.
데이터베이스를 따로 구현하지 않고 구현할 것이다.
movies라는 배열을 만들고 형식을 만들어줄 것이다.
private movies: Movie[] = []
movies 폴더에 entities 폴더를 만들고 movie.entity.ts 파일을 만들었다.
// movie.entity.ts
export class Movie {
id: number;
title: string;
year: number;
genres: string[];
}
이제 영화 정보를 모두 가져오는 로직을 구현할 것이다.
getAll(): Movie[] {
return this.movies
}
서비스에서 로직을 구현하고나면 컨트롤러에서 어떻게 서비스에 접근해야 할까?
컨트롤러에서 constructor를 이용해야 한다.
constructor(private readonly MovieService: MoviesService){}
이렇게 해주면 서비스에 구현한 로직들을 사용할 수 있다.
@Get()
getAll(): Movie[] {
return this.movieService.getAll()
}
나머지 로직도 구현하면 된다.
private movies: Movie[] = []
getAll(): Movie[] {
return this.movies
}
getOne(id: string): Movie {
const movie = this.movies.find(movie => movie.id === +id)
if (!movie) {
throw new NotFoundException(`Not Found movie with id: ${id}`)
}
return movie
}
create(movieData) {
this.movies.push({
id: this.movies.length + 1,
...movieData
})
}
deleteOne(id: string) {
this.getOne(id)
this.movies = this.movies.filter(movie => movie.id !== +id)
}
updateOne(id: string, updateData) {
const movie = this.getOne(id)
this.deleteOne(id)
this.movies.push({...movie, ...updateData})
}
DTO
DTO는 Data Transfer Object의 약자로서, 데이터를 오브젝트로 변환하는 객체이다.
프로그래머가 코드를 더 간결하게 만들 수 있도록 해주며, NestJS가 들어오는 쿼리에 대해 유효성을 검사할 수 있게 해준다.
한번 createMovie DTO를 만들어보자.
export class CreateMovieRequestDTO {
readonly title: string;
readonly year: number;
readonly genres: string[];
}
이전에 엔티티를 만든 것처럼 만들어 주면 된다.
둘의 차이는 entity는 DB, DTO는 API라고 대충 생각하면 될 것 같다.
이렇게 하면 컨트롤러와 서비스에 있는 movieData의 타입으로 설정하면 된다.
Validation
데이터들의 유효성 검증을 하기 위해 몇 가지 설치해야 할 것이 있다.
npm i class-validator class-transformer
설치를 하고 나면 main.ts파일에 해당 코드를 추가해준다.
app.useGlobalPipes(
new ValidationPipe()
)
그러고 dto파일에서 해당 데코레이터를 사용해준다.
import { IsNumber, IsString } from "class-validator";
export class CreateMovieRequestDTO {
@IsString()
readonly title: string;
@IsNumber()
readonly year: number;
@IsString({each: true})
readonly genres: string[];
}
ValidationPipe의 인자로 whitelist와 forbidNonWhitelisted를 사용하면 보안을 더 강화할 수 있다.
app.useGlobalPipes(
new ValidationPipe({
whitelist: true,
forbidNonWhitelisted: true
})
whitelist를 true로 설정하면 유효성 검사기가 유효성 검사 데코레이터를 사용하지 않는 속성의 object를 제거한다.
forbidNonWhitelisted를 true로 설정하면 화이트리스트에 없는 속성을 제거하는 대신 유효성 검사기가 예외를 발생시킨다.
쉽게 말하자면 누군가 이상한 걸 보내면 리퀘스트 자체를 막아버리는 것이다.
transform을 사용하면 지정한 타입으로 페이로드를 자동 변환할 수 있다.
UpdateMovieRequestDto도 CreateMovieRequestDto처럼 만들어주면 된다.
UpdateMovieRequestDto는 CreateMovieRequestDto와 속성들이 같지만 필수적인 것은 아니다.
그래서 PartialType을 사용할 수 있다.
npm i @nestjs/mapped-types
커맨드 실행 후 UpdateMovieRequestDto에 해당 코드를 넣으면 된다.
import { PartialType } from "@nestjs/mapped-types";
import { CreateMovieRequestDto } from "./createMovie.dto";
export class UpdateMovieRequestDto extends PartialType(CreateMovieRequestDto) {}
Modules
app.module 파일에 바로 MovieController와 MovieService가 들어가있다. app.module에는 AppController와 AppService가 있는 것이 좋다. 그래서 구조를 변경할 것이다.
nest g mo
커맨드를 실행하면 MovieModule이 생성되면서 app.module에 auto로 적용이 될 것이다.
밑에 컨트롤러와 서비스는 AppController와 AppService로 변경할 것이기 때문에 이전에 들어간 값은 지워주자.
movie.module에 MoviesController와 MoviesService를 넣어주고 app.module에는 AppController과 AppService를 넣어주며 iMoviesModule을 import해준다.
'BACKEND > NestJS' 카테고리의 다른 글
NestJS Setup (0) | 2023.03.25 |
---|