Express를 활용해 개발을 하면서 늘 생각하던 점이 있다. 개발에 대한 자유도는 많아서 좋은데 그에 따라 협업할때 늘 새로 고려해야하는 점이 있었다.
규칙성을 제대로 확립하지 않으면 각자 사람마다 폴더구조도 다르고 한데 다른 Java의 Spring및 Spring boot와
Django 처럼 제대로 형식이 갖춰진 프레임워크가 나오면 좋겠다는 생각을 했고, 그렇게 생각만 하던 도중 Nest.js라는게 나왔다.
그래서 오늘은 nest.js를 설치해보고 그에따라 기본 폴더구조를 간단하게 진행해 보려 한다.
https://docs.nestjs.com/ 홈페이지 접속하면 nest를 이렇게 소개하고 있다.
Nest (NestJS)는 효율적이고 확장 가능한 Node.js 서버측 애플리케이션을 구축하기 위한 프레임워크입니다
Nest.js는 Typescript로 빌드및 지원을 하지만 순수 자바스크립트로도 개발이 가능하며 OOP(객체지향 프로그래밍),
FP(함수형 프로그래밍), FRP (함수형 반응형) 프로그래밍을 결합했다고 나와있다. 또한 내부 서버 프레임워크로써 express를 사용했다고 나와있다.
Spring및 Spring Boot, Django등을 경험해서 개발을 해본 나로써는 해당 nest.js가 정말 반가웠다. 협업을 할때 폴더구주와 변수이름만 잘 통해도 훨씬 수월했기 때문이다.
여기까지가 nest.js를 시작하게된 계기였다.
1.nest.js 설치하기
npm i -g @nestjs/cli
npm i -g 옵션을 통해 어느곳에서도 nest 명령어를 사용할 수 있게 글로벌 설치를 진행해준다.
그리고 폴더를 생성한 후
그후 터미널을 열어서
nest new .
해당 폴더 경로에 nest를 설치해줬다.
이제 각자 폴더에 대한 구조를 분석해 보려고 한다.
해당 내용을 보게 되면 기본적으로 3가지 구조가 보인다
- app.controller.ts -기본 컨트롤러
- app.controller.spec.ts - 컨트롤러에 대한 단위 테스트
- app.module.ts - application의 root module
- app.service.ts - default service
- main.ts - NestFactory를 활용해 Nest 애플리케이션 생성
여기까지 기본 역할에 대해 알아보고
실전으로 보고 파악을 하는 타입인 나는 보통
흐름을 파악 + 모르는 내용을 해당 프레임워크나 라이브러리의 document로 보면서 파악하는편이다.
폴더 구조를 보니까 main.ts가 존재한다.
보통 main, index가 시작점이라 이것부터 보고 파악하려고 한다.
main.ts
여기서 외부 NestFactory안에 인자로 AppModule을 담아서 create하고있다. 또한 해당 앱을 3000번 포트로 실행하고 있다.
그럼 이제 NestFactory에 대해서 알아보겠다.
위 내용을 번역기로 해석하면
module 매개변수를 통해 애플리케이션에 필요한 루트 모듈을 전달합니다. 관례상 일반적으로 ApplicationModule이라고 합니다. 이 모듈부터 Nest는 종속성 그래프를 어셈블하고 종속성 주입 프로세스를 시작하고 애플리케이션을 시작하는 데 필요한 클래스를 인스턴스화합니다.
따라서 NestFactory.create는 종속성 주입관련 프로세스가 셋팅된 NestApplication을 AppModule을 인자로 받아서
생성한다. 즉 AppModule을 인자로 받아서 NestApp을 생성한다.
인자로받은 AppModule에 대해 파악하기 위해서 해당 app.module.ts를 보며 해당 모듈에 어떠한 정보가 있는지 파악해보겠다.
일단 해당 코드를 보면
@Module과 controllers로 AppController를 , providers로 AppService를 나타내고있다.
여기에서 @로 시작된 해당 함수는 어떤것일까? 하는 생각이 들 수 있다.
@는 Decorator 패턴으로써 데코레이터는 클래스, 메서드 또는 속성에 대해 정의할 수 있다. 주석을 달듯이 해당 데코레이터를 선언하면 해당 정의된 속성을 주입받아 사용이 가능하다.
@Module
providers | Nest injector 에 의해 인스턴스화되고 적어도 이 모듈에서 공유될 수 있는 제공자 |
controllers | 인스턴스화해야 하는 이 모듈에 정의된 컨트롤러 세트 |
imports | 이 모듈에 필요한 공급자를 내보내는 가져온 모듈 목록 |
exports | 그 하위 집합은 providers이 모듈에서 제공하며 이 모듈을 가져오는 다른 모듈에서 사용할 수 있어야 합니다. |
해당 Module에서는 App Controller와 AppService를 묶어서 하나의 덩어리로 만들어주는 역할을 하고 있다.
이제 해당 App Controller로 이동을 해보겠다.
app.controller.ts
@Controller
컨트롤러는 들어오는 요청(GET,POST,PATCH,DELETE 등) 을 처리 하고 클라이언트에 응답 을 반환 하는 역할 을 한다.
해당 컨트롤러를 보면 @GET 방식으로 요청이 도달하게 되면 appService에 있는 Hello 함수를 호출하게 되어있다.
마지막으로 app.service를 보겠다
service
service는 비즈니스 로직을 분리하기위해 존재하는 파트이다.
비즈니스 로직이란 실제 사용자에게는 보이지 않지만 해당 내용을 수행하기 위해 주고받는 모든 과정을 비즈니스 로직이라 한다.
그럼 이 비즈니스 로직을 왜 컨트롤러에서 분해해서 컨트롤러에서는 호출만 할까?
그건 재사용성 때문이다. 다른곳에서도 해당 비즈니스 로직이 사용될 수 있기 때문에 분할해서 사용한다.
app.service.ts
해당 서비스를 보면 방금 호출했던 getHello에 대한 정의가 나와있고
또한 @Injectable() 이라는 데코레이터가 존재한다.
@Injectable
해당 Injectable 데코레이터는 해당 class가 의존성으로 주입(DI)될 수 있다고 정의해준다.
여기서 의존성주입(DI)는 는 Dependency Injection의 줄임말로써 외부에서 정의한 class및 메서드를 내부에 주입해서 사용할수 있게 만드는 방법이다.
따라서 여기서의 Injectable은 해당 @Injectable를 부여하면 다른곳에서도 해당 service를 사용할수 있게끔 설정해주는것이 Injectable이라 할 수 있겠다.
정리
여기까지 본 바로는 main.ts에서 module을 기반으로 nest App 생성및 특정포트로 listen ->
localhost:3000/ GET 방식으로 요청을 보내게 되면 app.controller.s 내 @GET 으로 정의된곳에 도착
-> 도착후 appService의 getHello() 실행 -> 'Hello World' 가 리턴되는 방식이라 할수 있겠다.
앞으로의 개발방식도 위와같이 Module 지정 -> 컨트롤러로 전송 -> 컨트롤러에서는 서비스 호출 방식으로 개발을 진행하면 될 것 같다.