Node.js , Express 기반 서버사이드 프레임워크
Nest.JS 의 기본 셋팅값 (추가 설정 없이 사용 가능)
1. Typescript | 타입 안정성 확보
2. Jest | 유닛테스트, e2e테스트로 서비스 안정성 확보
3. Fastify | @Req, @Res 외에 퍼포먼스 확보
npm i @nestjs/graphql@^7 graphql@^15 apollo-server-express@^2
npm install --save @nestjs/typeorm
npm install @nestjs/sequelize
https://github.com/unchaptered/21-11-lecture-nestjs
DI 에 대한 더욱 구체적인 내용과 구현은 기회가 된다면 다른 포스트에서 제대로 파고 들어가도록 해야겠다.
클래스에 대한 의존성의 인터페이스를 통한
코드 유연성 증대 및 클래스의 인스턴스를 외부에서 생성하여 주입
import { MovieService } from "./movies.service";
@Module({
controller: [MoviesController],
providers: [MoviesService],
})
export class MoviesModule {}
Nest.JS 가
providers 항목들 을 뽑아와서
controller 안 에 inject(주입) 한다.
Express 프레임워크는 Request, Response 속성을 쉽게 사용할 수 있다.
export const getAllMovies=(req,res)=>{
const { ... }=req;
}
Nest 프레임워크에서도 사용이 가능하다.
import { Controller, Get, Req, Res } from "@nestjs/common";
import { Movie } from "./entities/movie.entity";
import { MovieService } from "./movies.service";
@Controller("movies")
export const MoviesController{
@Get()
getAllMovies(@Rea() req, @Res() res):Movie[] {
return this.movieService.getAllMovies();
}
}
Nest.JS 에서는 성능 상의 이유로 Fastify 라이브러리 사용을 추천한다.
Jest 라이브러리에 대한 자세한 점들은 따로 포스트를 작성하도록 하겠다.
Jest 는 유닛테스트 및 e2e테스트 라이브러리이다.
아래는 Nest.JS 로 생성한 프로젝트의 package.json 의 script 항목이다.
"scripts": {
...
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
purpose : 유닛테스트 실행
purpose : 프로젝트 테스트 실행
Nest.JS 는 최종적으로 하나의 APP 으로 이루어져 있다.
해당 APP 이 각각의 모듈로 연결되어 있으며, 전술한 의존성 담당하고 있다.
@Module({
import: [ModuleName], // 다른 모듈 임포트
controller: [ControllerName], // 반환메서드
provider: [ServiceName] // 클래스와 메서드 구현부
});
@Injectable()
export class ServiceName {
private movies: Movie[]=[];
getAllMovies(): Movie[] {
return this.movies;
}
getSingleMovie(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;
}
deleteSingleMovie(id:number) {
this.getSingleMovie(id);
this.movies=this.movies.filter(movie=>movie.id!==+id);
}
patchPartOfMovie(id:number, updateData:UpdateMovieDto) {
const movie=this.getSingleMovie(id);
this.deleteSingleMovie(id);
this.movies.push({ ...movie, ...updateData });
}
}
controller 는 express 의 router-controller 와 동일한 역할을 합니다.
Decorator 가 URL 을 받아서 function 안의 기능을 실행시킵니다.
function 뒤의 괄호 () 에서 여러 가지 값들을 받을 수 있습니다.
단, 여기에 적어놓지 않은 값들은 받지 않습니다.
(express.js 에서는 받아졌고 사용의 유무만 결정했다.)
controller 에서 사용할 수 있는 키워드는 다음과 같습니다.
@Get : 수신
@Post : API 송신
@Delete : 삭제
@Put : 모든 리소스 업데이트
@Patch : 일부 리소스 업데이트
@Controller("movies")
export class MovieController {
constructor(private readonly moviesService: MoviesService) {}
@Get // https methods
getAllMovies():Movie[] {
return this.moviesService.getAllMovies();
}
@Get("search") // https methods
searchSingleMovie(@Query("year") year:string) {
return `We are searching for a movie made after ${year}`;
}
@Get(":id") // https methods
getSingleMovie(@Param("id") movieID:number) {
return this.moviesService.getSingleMovie(movieID);
}
// ... more functions ...
}
import { IsNumber, IsOptional, IsString } from "class-validator";
export class CreateMovieDto{
@IsString() // in "class-validator"
readonly title: string;
@IsNumber()
readonly year: number;
@IsOptional()
@IsString({ each: true })
readonly genres: string[];
}
타입스크립트는 사용할 객체 타입을 따로 entity 라고 선언해두어야 한다.
export class Movie{
id: number;
title: string;
year: number;
genres: string[];
}