Nest.js는 Node.js 서버사이드 애플리케이션을 만드는 프레임워크다.
타입스크립트를 완벽하게 지원하며, 오픈소스 프로젝트다.
기본적으로 Express를 이용해서 HTTP 통신을 하며 Fastify를 사용할 수도 있다.
공식 홈페이지에서는 두가지 설치 방법을 설명하고 있다.
$ npm i -g @nestjs/cli
$ nest new project-name
첫째는 @nestjs/cli 모듈을 사용하는 것이고,
$ git clone https://github.com/nestjs/typescript-starter.git project
$ cd project
$ npm install
$ npm run start
둘째는 스타터 프로젝트를 클론하여 사용하는 것이다.
위에 링크한 깃 저장소에 nest에서 공식으로 지원하는 여러 서버 애플리케이션 샘플을 참고할 수도 있다.
Nest.js는 기본적으로 컨트롤러 - 프로바이더 - 모듈 구조로 애플리케이션을 구성한다.
클라이언트로부터 HTTP 요청이 nest 서버에 들어오면 라우팅 메커니즘에 따라 알맞은 컨트롤러로 요청이 분배된다.
컨트롤러는 HTTP 요청을 받아서 메소드를 수행하고 결과를 클라이언트로 리턴한다.
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
@Get()
findAll(): string {
return 'This action returns all cats';
}
}
공식 문서의 예제 코드를 보면 @nestjs/common 모듈으로부터 Controller와 Get 애노테이션을 임포트해서 Cats 컨트롤러 클래스를 만들고 있다.
@Controller('cats')는 '/cats' 경로에 요청이 오면 해당 컨트롤러를 참조하겠다는 뜻이 된다.
바로 아래에 @Get()는 '/cats' 경로에 Get 메서드로 요청이 오면 해당 함수를 실행하겠다는 뜻이 된다.
결과적으로 클라이언트가 'http://{domain}/cats' 에 Get 메서드로 요청을 보내면 클라이언트는 'This action returns all cats'라는 문자열을 서버로부터 리턴받을 것이다.
프로바이더는 Nest.js의 근본적인 개념으로, 수많은 Nest 기본 클래스들이 프로바이더로 취급된다.
프로바이더의 핵심은 --마치 자바 스프링처럼-- 의존성 주입(Dependency Injection)을 통해 관리한다는 것이다.
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
다시 예제 코드다. 이번엔 CatsService라는 클래스를 만들었다. @Injectable 애노테이션을 임포트해서 사용하고 있는데, 이름 그대로 다른 클래스에서 의존성을 주입할 수 있게 해준다.
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
위에서 만든 프로바이더(CatsService)는 이렇게 컨트롤러에서 호출해서 사용할 수 있다.
마지막으로 모듈이다. 모듈은 컨트롤러와 마찬가지로 @Module 애노테이션을 임포트하여 사용한다.
모듈은 Nest가 애플리케이션의 계층 구조를 만들 수 있도록 메타데이터를 전달해준다.
Nest 애플리케이션은 기본적으로 root module이라고 하는 기본 모듈을 가진다.
root module은 Nest가 각 모듈과 프로바이더의 관계성, 의존성을 확인할 수 있게하는 애플리케이션 그래프의 시작점이 된다.
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class CatsModule {}
다시 예제 코드로 돌아와서, 앞서 만들었던 컨트롤러와 프로바이더를 포함하는 CatsModule을 만들었다.
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
})
export class AppModule {}
CatsModule은 다시 AppModule(root module)에서 임포트하여 Nest 애플리케이션에서 사용한다.