Nest.js

Nest, Next, Nuxt… 이름은 비슷해보여도 서로 전혀 다른 프레임워크이다. 이름을 같은 자리에서 동시에 지었나

Express만을 이용하여 Node.js 개발을 하다보면 다른 언어에서는 찾아볼 수 없는 자유에 취하다가, 모든 것을 개발자에게 맡기는 그 자유때문에 서비스의 규모가 커질수록 유지보수, 테스트가 어려워지고 코드도 난해해지기 일쑤다. 그래서 Typescript를 적용해서 Node.ts 환경으로 코드를 작성하면 훨씬 나아지지만, 초기 설정에는 시간과 비용이 든다. OOP(Object Oriented Programming)보다 Functional Programming에 익숙한 나는 타입스크립트를 적용한 환경에서도 모듈, 컨트롤러들의 배치와 구조를 결국 내 생각대로 짰어야 했다. 그 모든 비효율을 잡아주는 프레임워크가 Nest.js이다.

이번에 Nest.js를 공부하면서 정말 1시간에 한번은 감탄한 것 같다. 대단할 정도로 구조를 잘 잡아주고, 테스트 파일(Jest)도 자동으로 생성해주고, import도 자동으로 해준다. 장점도 무궁무진하지만 소규모 프로젝트에는 시간, 비용이 역으로 들 수도 있으니 어느 정도 규모가 있는 프로젝트를 체계적으로 구축하고 싶을 때 망설임없이 사용해도 되겠다고 생각했다.

설치

1
$ npm i -g @nestjs/cli

설치는 npm global로 설치하면 된다. yarn global add는 설치가 되는 것처럼 보여도 문제가 생긴다. yarn 신봉자이지만 이번엔 npm으로 설치했다.

프로젝트 시작

1
$ nest new first-nest-project

프로젝트가 만들어지면 모든 초기 폴더와 파일들이 세팅된다. 대부분의 작업은 src에서 진행될 것이고, end-to-end 테스트에는 test 폴더 내부에서 작업할 것이다.

src의 구조는 다음과 같다.

1
2
3
4
5
├── src
├── app.controller.ts
├── app.service.ts
├── app.module.ts
├── main.ts

Nest 관점에서 OOP의 이해

모듈

모듈의 구조

모듈은 어플리케이션의 일부분이다. 한 어플리케이션 안에는 루트 모듈(Root Module)이 1개 존재하고, 그 루트 모듈 하위에 여러가지 모듈이 import된다. 그림처럼 Users, Orders, Chat 3가지 각각 다른 역할의 어플리케이션의 일부분은 루트 모듈 하위에 들어간다. Nest에서는 @Module() 데코레이터로 모듈을 정의한다.

컨트롤러

컨트롤러의 구조

컨트롤러는 Express의 라우터 개념이다. 클라이언트의 Request를 받고 Response를 반환해준다. uri로 전달받은 요청을 프로바이더로 넘겨준다.

프로바이더 (서비스)

프로바이더의 구조

컨트롤러에서 받은 요청을 처리하는 비즈니스 로직을 정의하는 부분이다. Nest는 컨트롤러를 비즈니스 로직(서비스)와 구분짓고 싶어한다.

Dependency Injection: 컨트롤러에서 서비스를 불러올 때 Nest가 서비스를 import하고 컨트롤러에 의존성을 주입(inject)하는 과정이다. 그래서 서비스에는 @Injectable() 데코레이터를 붙인다. 결국 컨트롤러에서 직접 import하지 않아도 된다.

generate 사용하기

Root 구조(app.module, app.controller, app.service)는 자동으로 초기에 잡아준다. 그러면 다른 파일은 직접 작성해야 할까? 사실 이 부분에서 감동이었다. 명령어 몇 자만 치면 내가 원하는 파일을 만들고, .spec 파일을 만들고(나중에 유닛 테스트시 필요한 파일이다), App Module(루트 모듈)에 자동으로 import도 시켜준다. (여기다가 vscode extension 중 auto import라는 툴을 같이 사용하면 코드 꼭대기에서 import… 를 직접 칠 일이 없다)

nest를 쳐보자

nest 명령어

쉘에 nest를 입력하면 generate 옵션들이 나온다. 위에서 말한 모듈, 컨트롤러, 서비스(프로바이더)가 목록에 있다. 이외에도 graphql 리졸버까지 자동으로 만들어준다.

nest g

generate는 g로 대체할 수 있고, 위 목록에서 name을 전부 치지 않고 alias만 쳐도 된다.

그러니까 모듈은 nest g mo, 컨트롤러는 nest g co, 서비스는 nest g s로 만들 수 있다.

예를 들어 컨트롤러를 만들기 위해 nest g co를 입력하면

nest g co 입력시

이렇게 컨트롤러의 이름을 묻는다. 내가 원하는 이름으로 해주면 되는데, 그에 따른 모듈과 서비스의 이름도 동일하게 만들면 된다. 그러면 한 폴더에서 자동으로 서로 엮어준다.

지금은 Nest.js에 대한 기초 공부를 모두 마친 상태인데, 다시 정리할 겸 적고 있다. 앞으로 Pure Express 어플리케이션을 만들 일이 있을까 싶다. 공부하다 보면 얼마전에 맛만 본 Spring Boot와 정말 비슷한 느낌이 드는데, 난 개인적으로 Java보다 Typescript가 더 좋다. 그래서 Nest.js는 3일동안 정말 흥미롭게 공부했고 푹 빠졌다.