NestJS는 Node.js의 서버 측 애플리케이션을 구축하기 위해 사용하는 프레임 워크이다. NestJS의 장점은 아래와 같다.
TypeScript로 빌드된다.
프로젝트 생성 시 사용자가 TypeScript 관련 모듈을 설치하고 설정하지 않아도 자동으로 해준다. JS로의 컴파일 설정도 되어 있어 default로 설정된 /dist에 JS코드로 컴파일된다.
vanilla JS로도 개발이 가능하며 이러한 경우 Babel 컴파일러가 필요하다.
eslint, prettier, jest 설치 및 설정을 자동으로 해준다.
OOP, FP, FRP 요소를 결합하여 사용할 수 있다.
모듈식 아키텍처로 복잡한 애플리케이션을 더 쉽게 관리하고 코드 품질을 유지할 수 있다.
이렇게 많은 부분들을 대신해주는 NestJS, 어떻게 사용하고 어떻게 구성되어 있는지 알아보자~!
NestJS를 사용하려면 당연하게도 JS runtime인 Node.js가 설치되어 있어야 한다. 준비가 되었다면 NestJS를 설치하고 프로젝트를 만들어보자.
$ npm i -g @nestjs/cli
$ nest new project-name
위 명령어를 실행하면 아래와 같은 구조의 프로젝트가 생성된다.

TypeScript, eslint, prettier, jest에 대한 설정이 되어 있고, .git 폴더(로컬 저장소)가 생성된다. github으로 프로젝트를 관리하기 위해 나의 github repository와 연동이 필요하다.
src의 요소를 살펴보자.
src
├── app.controller.spec.ts # 컨트롤러에 대한 단위 테스트
├── app.controller.ts # 단일 경로(루트)가 있는 기본 컨트롤러
├── app.module.ts # 애플리케이션의 루트 모듈
├── app.service.ts # DB, dto 관리
└── main.ts # entry file
main.ts에서 NestFactory 클래스의 인스턴스를 생성(= 앱 생성)하며 시작한다.

전체적인 구조를 보았을 때 app module에 프로젝트를 구성하는 모듈들이 있고, 이 각각의 모듈은 자신의 controller, service, entity, repository 등을 가지고 있다.

NestJS의 큰 흐름을 보면 client로부터 들어온 요청이 controller - service로 가서 처리되고 이에 대한 response를 반환하는 흐름을 가진다.
이제 하나씩 살펴보며 어떤 역할을 하고 어떻게 생성하는지 알아보자!
모듈은 @Module() 데코레이터로 주석이 달린 클래스인데 이 데코레이터는 애플리케이션 구조를 구성하는데 사용하는 메타데이터를 제공한다.

각 응용프로그램은 root module인 Application Module은 기본적으로 가지고 있고, root module은 Nest가 module과 provider의 관계, 종속성 등을 다루는 시작점이 된다.
모듈은 밀접하게 관련된 기능의 집합이다. 또한 모듈은 기본적으로 싱글톤으로 여러 모듈 간에 동일한 인스턴스를 공유하여 사용할 수 있다. 즉, Example Module을 Users Module, Orders Module 등에서 사용할 수 있다는 것이다.
프로젝트 생성 시 기본으로 세팅된 것들을 지우고 처음부터 만들어보겠다. src에서 app.module.ts, main.ts를 제외한 파일은 모두 삭제하고, test 폴더도 삭제하면 된다. 그리고 다음 명령어로 Module을 생성한다.
$ nest g module module-name
* g : generate

이렇게 하면 src 아래 module이 생성된다. 초기에는 module 파일만 존재하며 이제 필요한 controller, service 등을 하나씩 만들어줘야 한다.
controller는 client로부터 요청을 받아 처리하고 응답을 반환한다.
@Controller('posts')
export class PostsController {
@Get()
getPosts(): string {
return 'All Posts.'
}
}
basic controller는 @Controller() 데코레이터로 클래스를 데코레이션(데코레이터를 붙임)하여 정의되는데 이 데코레이터의 인자는 path를 받는다. 위 예시의 경우 /posts로 시작하는 url 요청은 모두 PostsController로 라우팅되는 것이다. 이 컨트롤러로 라우팅된 후부터는 path에서 /posts를 반복할 필요가 없어진다.
@Get()은 HTTP request method decorator로 /posts path로 GET 요청이 들어올 경우 getPosts() method가 실행된다. 여기에 추가적인 path를 적을 수 있는데 @Get('popular')으로 작성하면 /posts와 결합되어 posts/popular path의 GET 요청을 처리하게 된다.
HTTP request method decorator에는 @Get()뿐만 아니라, standard HTTP method인 @Post(), @Put(), @Delete(), @Patch(), @Options(), @Head()을 모두 지원한다. 추가적으로 이 모든 method를 다루는 @All()도 있다.
$ nest g controller module-name --no-spec
* --no-spec : 테스트를 위한 소스코드 생성 X

위의 명령어로 controller를 생성하면 posts directory에 controller file이 먼저 생기고(CREATE), 같은 위치의 module file을 찾아 controller를 등록(UPDATE)하게 된다.
provider에는 services, repositories, factories, helpers 등이 있다.
@Injectable()
export class PostsService {
private readonly posts: Post[] = [];
create(post: Post) {
this.posts.push(post);
}
}
provider에서 주목할 점은 종속성 주입인데, 예를 들어 Service A, Service B를 Controller A에 종속시킬 수 있다. 바로 @Ingectable을 이용하는 것인데 이 데코레이터를 붙이면 Nest의 IoC에 의해 관리된다.(IoC와 DI는 다음 번에 더 자세히 알아보자) 즉, 다른 클래스에서 의존성으로 사용할 수 있는(주입가능한) 상태가 되는 것이다.
@Controller('posts')
export class PostsController {
constructor(private postsService: PostsService) {}
// 'private'을 생성자 파라미터에 바로 작성하면 선언과 초기화를 한 번에 가능(shorthand)
...
}
injectable한 PostsService를 PostsController의 constructor에 주입할 수 있게 된다. 이와 같이 객체는 서로 다양한 관계를 만들 수 있다.

그리고 controller는 요청을 처리할 때 복잡한 작업을 provider에게 위임한다. provider가 처리하고 결과를 controller에게 반환해준다.
Service는 보통 데이터 저장, 검색 등의 로직을 처리한다.
$ nest g service module-name --no-spec

위 명령어로 service file을 먼저 생성(CREATE)하고 이 service를 사용하기 위해서 module의 provider에 등록(UPDATE)해준다.
https://docs.nestjs.com/
https://www.youtube.com/watch?v=3JminDpCJNE&t=2032s