Javascript/NestJS

NestJS Provider, Service에 대해 알아보기

kyoulho 2023. 3. 22. 22:01

NestJS의 Provider 란?

 프로바이더는 Nest의 기본 개념입니다. 대부분의 기본 Nest 클래스는 서비스, 리포지토리, 팩토리, 헬퍼 등 Provider로 취급될 수 있습니다. 프로바이더의 주요 아이디어는 종속성으로 주입할 수 있다는 것입니다. 즉, 객체는 서로 다양한 관계를 만들 수 있으며 객체의 인스턴스를 연결하는 기능은 대부분 Nest 런타임 시스템에 위임될 수 있습니다. 

 위에 글은 NestJS 에서 설명하는 Provider를 번역한 글입니다. 저는 이글을 보고 Provider를 스프링의 Bean이라고 이해했습니다. 애플리케이션에서 사용되는 객체를 정의하고, 의존성 주입 시스템에 등록하며 인스턴스를 필요한 곳에 제공한다는 점이 Bean과의 공통점이지만 Bean은 기본적으로 Singletone이고 Provider는 Transient로 등록된다는 차이점이 있습니다.

 

Transient란?
객체를 생성할 때마다 새로운 인스턴스를 생성하여 반환하는 방식을 의미합니다. 다시 말해, Transient로 등록된 객체는 요청이 있을 때마다 매번 새로운 인스턴스를 생성합니다. Transient로 등록된 객체는 매번 새로운 인스턴스를 생성하므로 메모리 사용량이 늘어날 수 있습니다. 하지만 상태를 유지하지 않고 매번 새로운 상태에서 작업하는 경우에는 Transient가 적합하다고 할 수 있겠지요.

 

Provider 클래스는 @Injectable 데코레이터를 사용하여 생성됩니다. 이 데코레이터를 사용하면 해당 클래스를 NestJS의 DI 컨테이너, NestApplicationContext에 등록할 수 있습니다. DI 컨테이너는 Provider를 생성하고 관리하며, 필요한 곳에서 인스턴스를 제공합니다.

Provider를 주입 받고자하는 클래스에서는 생성자를 통해서 주입받을 수 있습니다. 만약 다른 모듈에서 주입받고자 한다면 주입받고자 하는 클래스의 상위 모듈에 Provider로 등록하거나 해당 Provider의 상위 모듈을 import하여 사용할 수 있습니다.

Provider 생성하기

Provider 또한 커맨드로 생성합니다

nest g provider [프로바이더 이름]

@Injectable 데코레이터가 붙은 Boards 클래스가 생성되었으며 boards.module.ts 파일에는 provider에 Boards 클래스가 자동으로 추가 되었습니다.

 

NestJS의 Service란?

 NestJS에는 nest g provider 명령어 말고도 **nest g service** 명령어가 별도로 존재합니다. 그렇다면 둘은 어떻게 다른걸까요?

 일반적으로 nest generate provider는 NestJS에서 다양한 클래스를 관리하는 DI 시스템에서 사용되는 클래스를 만들 때 사용합니다. 반면에, nest generate service는 비즈니스 로직을 담당하는 Provider 클래스를 만들 때 사용합니다. 이 Service는 주로 컨트롤러에서 사용되어 요청을 처리하고, 데이터를 조작하며, 다른 Provider 클래스를 주입받아 로직을 구현합니다.

 따라서 Provider는 NestJS의 DI 시스템에서 사용되는 모든 클래스를 지칭하는 개념이며, Service는 비즈니스 로직을 담당하는 Provider 클래스를 지칭한다고 할 수 있겠습니다.

그래서, nest generate providernest generate service는 Provider를 생성하는 명령어이지만, 각각의 용도에 따라 명령어가 분리되어 있는 것 같습니다.

Service 생성하기

nest g service [서비스 이름]

 

의존성 주입

NestJS에서는 생성자 주입(Constructor Injection) 방식을 사용하여 의존성을 주입합니다. 스프링의 @Autowired 같은 setter 방식의 의존성 주입은 지원하지 않지만 인터페이스 방식은 지원합니다.

@Controller('boards')
export class BoardsController {
  boardsService: BoardsService;

  constructor(boardsService: BoardsService) {
    this.boardsService = boardsService;
  }
}

BoardsController 에서 BoardsService를 생성자를 통해 의존성 주입하였습니다. 그런데 여기서 Typescript의 도움을 받으면 더 짧고 가독성 높은 코드로 바꿀수 있습니다.

 

Typescript 접근 제어자 이용하기

Javascript 에는 접근 제어자가 존재하지 않지만 Typescript 에는 3가지 접근 제어자를 지원합니다.

  • public: 어디서나 접근 가능
  • private: 해당 클래스 내부에서만 접근 가능
  • protected: 해당 클래스 내부 및 해당 클래스를 상속 받은 자식 클래스에서만 접근 가능

접근 제어자를 생성자 파라미터에 선언하면 접근 제어자가 사용된 생성자 파라미터는 암묵적으로 클래스 프로퍼티로 선언됩니다.

import { Controller } from '@nestjs/common';
import { BoardsService } from './boards.service';

@Controller('boards')
export class BoardsController {
  constructor(private boardsService: BoardsService) {}
}

Javascript로 컴파일될 때는 private 키워드가 사라지고 다음과 같이 생성자 파라미터만 남게 됩니다.