lottie
Seungjun's blog
blog
nestjs docs 1편

   먼저 nest가 따르는 주요한 패러다임인 의존성 주입에 대해 정리 해보자.


 의존성 주입이란 DI(dependency injection)은 객체가 의존하는 또 다른 객체를 외부에서 선언하고 이를 주입받아 사용하는 것이다. 이는 OOP(object orient programming)의 한 디자인 패턴으로 nest의 근간이 되는 패러다임이다.

  Nest (NestJS)는 자바스크립트를 사용하며, TypeScript를 완전히 지원합니다 (순수 자바스크립트도 가능) 그리고 OOP(Object Oriented Programming), FP (Functional Programming) 및 FRP(Functional Reactive Programming) 요소를 지닌다.


  Nest는 Express와 같은 강력한 HTTP 서버 프레임워크를 사용하지만, Fastify를 선택적으로 구성하여 사용할 수도 있다.

Nest는 높은 추상화 수준을 제공하지만, 그들의 API를 개발자에게 직접 노출시킨다. 이는 기본 플랫폼에서 사용 가능한 서드파티 모듈을 사용할 수 있는 자유를 개발자에게 제공한다. 즉 express 나 fastify에서 사용 가능한 패키지들은 nest에서 사용 가능하도록 만들었다.


Install

$ npm i -g @nestjs/cli
$ yarn add -g @nestjs/cli 
$ nest new project-name

First steps

설치가 완료되면 노드 모듈과 몇 가지 기본 파일이 설치되며, src/ 디렉토리가 생성되고 아래의 핵심 파일이 생성된다.

파일

기능

app.controller.ts

하나의 라우트를 가진 기본 컨트롤러입니다.

app.controller.spec.ts

컨트롤러의 유닛 테스트입니다.

app.module.ts

애플리케이션의 루트 모듈입니다.

app.service.ts

하나의 메소드를 가진 기본 서비스입니다.

main.ts

NestFactory의 핵심 함수를 사용하여 Nest 애플리케이션 인스턴스를 생성하는 애플리케이션의 엔트리 파일입니다.

main.ts에는 앱을 부트스트랩 할 async 함수가 포함되어 있습니다.


// main.ts 
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

 Nest 앱 인스턴스를 생성하려면, core NestFactory 클래스를 사용합니다. NestFactory는 앱 인스턴스를 생성하는 몇 가지 정적 메소드를 제시합니다. create() 메소드는 INestApplication 인터페이스를 충족하는 애플리케이션 객체를 반환합니다. 이 객체는 다음 장에서 설명하는 일련의 메소드를 제공합니다. 앞서 나온 main.ts 예제에서는 단순히 HTTP 리스너를 시작하여 들어오는 HTTP 요청을 기다립니다.


 참고로, Nest CLI로 구성된 프로젝트는 각 모듈을 별도의 디렉토리에 유지하도록 권장하는 초기 프로젝트 구조를 생성합니다.


Platform

    Nest는 플랫폼에 독립적인 프레임워크를 지향합니다. 플랫폼 독립성은 개발자들이 여러 종류의 애플리케이션에서 재사용 가능한 논리적인 부분을 만들 수 있게 합니다.

 기술적으로, 어댑터가 생성되면 Nest는 어떤 Node HTTP 프레임워크와도 작동할 수 있습니다. 기본으로는 두 가지 HTTP 플랫폼 (express와 fastify)이 지원됩니다. 사용자의 요구에 맞게 선택할 수 있습니다.

  • platform-express: Node의 잘 알려진 최소한의 웹 프레임워크입니다. 이는 커뮤니티에 의해 구현된 많은 리소스가 있는 베틀 테스트되고 프로덕션에 사용 가능한 라이브러리입니다. 기본적으로 @nestjs/platform-express 패키지가 사용됩니다. 많은 사용자들은 express로 충분히 사용할 수 있으며, 별도의 작업을 수행하지 않아도 됩니다.

  • platform-fastify: 최대 효율성과 속도를 제공하기 위해 매우 집중한 고성능 및 저오버헤드 프레임워크입니다.

 아래 예시처럼 NestFactory.create() 메서드에 타입을 전달하면 app 객체는 해당 플랫폼에만 존재하는 메서드를 사용할 수 있습니다. 그러나 기본적으로는 플랫폼 API에 접근할 필요가 없는 경우에 한해 타입을 지정하지 않아도 됩니다.


const app = await NestFactory.create<NestExpressApplication>(AppModule);


Running the application

 설치 프로세스가 완료되면, 다음 명령을 운영 체제 커맨드 프롬프트에서 실행하여 어플리케이션을 시작하여 들어오는 HTTP 요청을 수신할 수 있습니다:

$ npm run start

 이 명령은 HTTP 서버가 src/main.ts 파일에서 정의된 포트에서 수신 대기하도록 앱을 시작합니다.


 파일 변경 사항을 감지하려면 다음 명령을 실행하여 애플리케이션을 시작할 수 있습니다:

$ npm run start:dev

 이 명령어는 파일을 계속 감시하여 자동으로 서버를 재컴파일하고 다시로드합니다.


Controllers(라우팅 담당)

   컨트롤러는 들어오는 요청을 처리하고 클라이언트에게 응답을 반환하는 역할을 담당합니다. 컨트롤러의 목적은 응용 프로그램의 특정 요청을 수신하는 것입니다. 라우팅 메커니즘은 어떤 컨트롤러가 어떤 요청을 받을지 제어합니다. 자주, 각 컨트롤러는 하나 이상의 라우트를 가지며, 다른 라우트는 서로 다른 작업을 수행할 수 있습니다.


 기본 컨트롤러를 만들기 위해, 우리는 클래스와 데코레이터를 사용합니다. 데코레이터는 클래스를 필요한 메타데이터와 연결하고, Nest가 라우팅 맵을 생성하여 (요청을 해당 컨트롤러에 연결하는) 라우팅을 지원합니다.


Routing

   다음에서는 기본 컨트롤러를 정의하는 데 필요한 @Controller() 데코레이터를 사용합니다. cats라는 선택적인 경로를 지정합니다. @Controller() 데코레이터에서 경로를 사용하면 관련 된 라우트 집합을 쉽게 그룹화하고 반복 코드를 최소화 할 수 있습니다.

 예를 들어, 고양이 엔티티와의 상호 작용을 관리하는 일련의 라우트를 /cats 경로 아래에 그룹화하려고 할 수 있습니다. 이 경우 파일의 각 라우트에서 해당 경로 부분을 반복하지 않도록 @Controller() 데코레이터에서 경로 접두사 cats를 지정할 수 있습니다.

// cats.controller.ts
import { Controller, Get } from '@nestjs/common';
@Controller('cats')
export class CatsController {
  @Get()
  findAll(): string {
    return 'This action returns all cats';
  }
}

   HTTP 요청 방법 데코레이터인 @Get()findAll() 메소드 앞에 붙어 Nest에게 HTTP 요청을 위한 엔드포인트 핸들러를 생성하도록 지시합니다. 이 엔드포인트는 HTTP 요청 방법(GET인 경우)과 라우트 경로에 대응합니다.


  라우트 경로란 무엇인가요? 핸들러의 라우트 경로는 컨트롤러에 선언된 (옵션으로 붙일 수 있는) 접두어와 메소드 데코레이터에서 지정한 경로를 연결하여 결정됩니다. 이 예제에서는 모든 라우트에 접두어로 cats를 선언했고, 데코레이터에서 경로 정보를 추가하지 않았으므로 Nest는 GET /cats 요청을 이 핸들러에 매핑합니다. 경로는 컨트롤러 경로 접두어와 요청 방법 데코레이터에서 선언한 경로 문자열을 모두 포함합니다. 예를 들어, cats 경로 접두어와 @Get('breed') 데코레이터를 결합하면 GET /cats/breed 요청과 매핑됩니다.


  위의 예에서 이 엔드포인트에 GET 요청이 들어오면 Nest는 우리가 정의한 findAll() 메소드로 요청을 라우팅합니다. 이 때 메소드 이름은 임의로 지정할 수 있습니다. 요청을 바인딩할 메소드를 선언해야 하지만, Nest는 메소드 이름에 대해 의미를 부여하지 않습니다.


 이 메소드는 200 상태 코드와 이에 상응하는 응답을 반환합니다. 왜 그럴까요? 이를 설명하기 위해 Nest가 응답을 조작하기 위해 사용하는 두 가지 다른 옵션을 먼저 소개해야 합니다.


옵션

기능

Standard (recommended)

이 내장 메소드를 사용하면 요청 핸들러가 자바스크립트 객체나 배열을 반환하면 자동으로 JSON으로 직렬화됩니다. 그러나 자바스크립트 기본형(예: 문자열, 숫자, 불리언)을 반환하면 Nest는 직렬화를 시도하지 않고 값만 보냅니다. 이를 통해 응답 처리가 간단해집니다: 값을 반환하면 Nest가 나머지 처리를 담당합니다. 또한 응답의 상태 코드는 기본적으로 항상 200입니다(POST 요청의 경우 201 사용). 핸들러 수준에서 @HttpCode(...) 데코레이터를 추가하여 이 동작을 쉽게 변경할 수 있습니다.

Library-specific

라이브러리(예: Express)별로 사용할 수 있는 express와 같은 라이브러리별 응답 처리 방식을 사용할 수 있습니다. 이를 위해 메소드 핸들러 시그니처에서 @Res() 데코레이터를 사용하여 주입할 수 있습니다(예: findAll(@Res() response)). 이 방식을 사용하면 해당 객체에서 노출된 네이티브 응답 처리 메소드를 사용할 수 있습니다. 예를 들어, Express에서는 response.status(200).send()와 같은 코드를 사용하여 응답을 구성할 수 있습니다.