이번 글에서 소개할 친구는 Nest JS입니다.
시스템 백엔드 개발에 대한 어떤 전문지식 없이
Express.js 로 개발을 해왔던 터라 기본적인 구조도 갖추지 않은채 중구난방으로 코드를 작성하고 많은 시행착오를 겪다보니 NestJS를 접했을 때 꽤나 큰 감동이 있었습니다.
위는 NestJS에 공식 홈페이지에 있는 소개글입니다. 위에서 볼 수 있듯이 NestJS 는TypeScript를 적극적으로 사용합니다. 최근 들어 Javascript로 만들어진 프로젝트들이 대부분 Typescript로 옮겨가고 있는 점들을 봤을 때 NestJS는 정확히 개발자들의 니즈를 파악하고 있는걸로 보이네요.
Nest JS CLI를 이용해 프로젝트를 시작하고나서 폴더 구조를 살펴보면
다음과 같습니다. Angular로 Frontend 개발을 했던 분이라면 module
, service
등의 구조가 익숙하실 겁니다. controller
부터 하나하나 각각의 역할을 살펴봅시다.
controller
는 기본적으로 client로 부터 들어오는 http request에 대한 응답을 처리해주는 역할을 합니다. 어떤 특정한 request가 들어오면 routing mechanism에 의해 어떤 컨트롤러가 어떤 request를 받을지 결정됩니다. 기본적으로 controller
를 생성하려면 decorator
를 사용해서 만듭니다. Decorator
는 클래스와 필요한 메타데이터를 연결짓는 역할을 합니다.
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
위와 같이 Cat이라는 Entity가 있고, 그와 관련한 Action들이 존재한다고 가정해봅시다. 한가지 예시밖에 없긴 하지만 @Get()
어노테이션을 통해서 /cats
로 GET Request가 들어올 때 findAll()
이라는 함수를 실행한다는 것을 알 수 있습니다.
모든 어플리케이션은 최소 하나의 모듈을 가지고 있고 가장 중심이 되는 root module은 Nest Application의 시작점이 됩니다. 물론 가장 조그만 어플리케이션은 이론적으로 root module 하나로도 작동을 할 수 있지만 흔한 케이스는 아닙니다. 어플리케이션을 유연하게 만들려면 이 모듈을 효율적으로 관리할 수 있어야 합니다. 위와 같이 목적에 따라 모듈을 분리하고 구조화 하면 좋습니다.
Service
는 데이터 저장소와 직접적으로 소통하는 역할을 합니다. 기본적으로 위에서 언급한 Controller
에서 불러져 실행되고 작성할 때는 기본적으로 @Injectable()
annotation을 맨 위에 씁니다.
예시를 볼까요?
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat){
this.cats.push(cat);
}
findAll(): Cat[]{
return this.cats;
}
}
Service에서는 두 가지 함수가 있습니다. create()
, findAll()
create는 DB에 직접 cat object를 받아서 저장하는 역할을 하는 함수이고, findAll은 모든 cat들을 검색하는 역할을 합니다. 새로운 내용은 바로 @Injectable()
데코레이터를 사용하는 것입니다.