나는 현재 node를 사용하는 백엔드 개발자이다. express를 이용해서 서버 개발을 하고 있으며 간간히 nuxt도 다루고 있다. 서버 개발 경험은 처음은 아니고 spring과 django를 이용해봤다. 아키텍쳐나 DI 같은 개념이 모호하게 느껴져서 spring으로부터 도망쳤는데 어쩌다보니 풀스택으로 취직해서 다시 백엔드를 공부하고 있다. 다행인건 node 개발자라는 것.
인프런과 공식문서를 확인하면서 nest를 공부한지 한달 정도 되었다. 배우는 이유는 node보다 편해보여서다. 정적 타입 언어인 typescript와 편리한 테스트, 이미 짜여진 아키텍쳐들... 안 배울 이유가 없어서 시작했는데 아직도 어렵다. 특히 spring에서 넘어온 개념들이 이해하기 어렵다. 앞으로 이 시리즈를 연재하면서 내가 궁금했던 nest의 기능들을 나만의 방식대로 정리할 예정이다. 특히 test를 정복하는 것이 목표이다. 첫 글에서는 nest 프로젝트 시작 시 기본적으로 생성되는 파일들을 확인하며 nestjs의 기초적인 개념을 정리할 것이다.
nest new project
위의 명령어로 프로젝트를 시작하면 nest-cli가 자동으로 프로젝트 스캐폴딩을 제공해준다.
nest의 시작은 main.ts의 bootstrap
함수 호출에서 출발한다. 이 함수는 nest가 서버 어플의 인스턴스를 생성하게 하고 3000번 포트와 연결하게 해준다. 여기서 말하는 서버 어플은 NestApplication
이다. 이 어플의 인스턴스는 NestFactory
라는 클라스를 통해 생성되며 그 과정에서 entry가 될 모듈을 지정할 수 있다.
모듈은 기본적으로 controller들과 provider들로 구성되어 있다. 일반적으로 controller는 라우팅 처리를 하고 provider는 비즈니스 로직을 처리한다. 이들을 모듈에 등록하기 위해서 Module
이라는 데코레이터에 메타데이터라고 불리는 객체를 파라미터로 넘겨줘야한다. 메타데이터의 controllers
에는 controller들을, providers에는 앞으로 언급할 service, repository 등등 injectable한 것들을 등록한다.
추가적으로, 모듈은 메타데이터의 imports를 통해 다른 모듈의 providers를 사용할 수 있다. 단, exports에 명시되지 않은 provider들은 다른 모듈에서 imports를 통한 사용이 불가능하다.
controller는 라우터 역할을 한다. Controller
데코레이터를 이용해 처리할 요청들의 주소(path)를 지정할 수 있다. 보통 prefix 지정이라고 한다. /
로 구분하는 이 주소의 다음 식별자는 보통 REST API의 메소드인 Get
, Post
, Patch
, Put
, Delete
데코레이터에 지정하는 편이다. 위의 예시에 getHello 함수는 prefix와 path가 지정되지 않았기 때문에 기본 값인 localhost:3000
으로 들어오는 GET 메소드의 HTTP 요청을 처리한다.
여기서 주의할 것은 DI이다. 의존성 주입이라고 부르는데, 모듈에 등록된 controller는 해당 모듈에 등록된 provider들을 constructor를 통해 이용할 수 있다. controller가 라우팅을 담당하고 비즈니스 로직은 provider가 담당할 수 있도록 설계된 것이다.
Injectable
데코레이터가 있다면 해당 클래스는 providers에 등록할 수 있다. nest의 DI 시스템이 해당 provider를 contructor 파라미터 주입을 통해 다른 클래스로 주입시킨다.
nest의 편리한 점 또 하나는 nest-cli를 통해서 controller를 생성하면 다음과 같은 테스트 파일을 같이 생성해서 제공해준다. 유닛 테스트를 위해서 이미 appController가 구현되어 있으며, 이것을 참조해서 테스트 케이스를 늘려가면 된다.