3. Provider

프로바이더는 Nest의 가장 기본적인 개념이다. Next 클래스 중 상당수인 서비스, 리포지토리, 팩토리, 헬퍼등이 프로바이더이다. 프로바이더는 종속성으로 주입될 수 있는 객체의 클래스이다. 이는 객체가 서로 다양한 관계를 생성할 수 있으며 이런한 객체를 "연결" 하는 기능이 주로 Next 런타임 시스템에 위임될 수 있다는 의미이다.

이전 장에서 간단한 CatsContoler를 만들었는데, 컨트롤러는 HTTP 요청을 처리하고 더 복잡한 작업을 프로바이더에게 위임해야한다. 프로바이더는 module 안에 providiers 로 선언된 순수 자바스크립트 클래스이다

 

힌트) Nest를 사용하면 보다 OO 방식으로 종속성을 설계하고 구성할 수 있으므로 SOLID 원칙을 따르는 것이 좋다.

 

서비스

간단한 CatsService를 작성해보자. 이 서비스는 데이터 저장 및 검색을 담당하며 CatsController에서 사용하도록 설계되었다. 이것 또한 프로바이더이다.

// cats.service.ts
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;
  }
}

힌트) CLI 를 사용하여 서비스를 생성하려면 아래와 같이 명령을 실행한다.

 nest g service cats

CatsService 는 프로퍼티 한개 두개의 메소드로 구성된 클래스다. 새로운 점은 @Injectable 데코레이터를 사용한다는 것이다. @Injectable 데코레이터는 CatsService가 Nest IoC 컨테이너에 관리되어야 한다는 메타데이터다 그런데, 아래 Cat 인터페이스를 보자.

// interfaces/cat.interface.ts
export interface Cat {
  name: string;
  age: number;
  breed: string;
}

아래 코드를 또 보면 CatsController 안에서 주입된 CatsService를 이용할 수 있다.

// cats.controller.ts

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는 CatsController의 생성자를 통해서 주입이 되는데. private 키워드를 통해서 선언과 초기화가 동시에 이루어 진다.

 

의존성 주입

Nest 는 일반적으로 의존성 주입이라고 알려진 디자인 패턴 기반으로 구축되었다. Nest에서는 TypeScript의  기능으로 종속성이 타입별로 리졸브되므로 종속성 관리가 매우 쉽다. 아래 예의 경우 Nest 는 catsService를 생성, 반환하면서 의존성을 리졸브한다. (또는, 일반적으로 싱글턴의 경우 이미 생성된 개체가 리턴된다. ) 이 의존성은 컨트롤러 생성자에게 리졸브되면서 전달된다. (혹은, 지정된 프로퍼티에 할당된다.)

constructor(private catsService: CatsService) {}

 

스코프

프로바이더는 일반적으로 애플리케이션 수명주기와 같은 수명주기를 갖는다. 애플리케이션이 기동되면 모든 종속성을 리졸브 하기위해서 모든 프로바이더를 인스턴스화 한다. 마찬가지로 애플리케이션이 종료되면 모든 프로바이는 삭제된다. 그러나 프로바이더의 수명주기를 지정하는 방법도 있다.

 

커스텀 프로바이더

Nest에는 프로바이더간의 관계를 해결하는 IoC 컨테이너가 내장되어 있다. 이 기능은 위에서 설명한 종속성 주입 기능의 기초가 되지만 실제로는 지금까지 설명한 것보다 훨씬 더 강력하다, 프로바이더를 정의하는 방법에는 여러 가지가 있는데, 일반 값, 클래스, 비동 또는 동기 팩토리를 사용 할 수 있다. 다른 장에서 다시 논하겠다.

 

선택적 프로바이더

경우에 따라 리졸브할 필요가 없는 종속성이 있을 수 있다. 예를 들어 구성 객체에 따라 달라질 수 있지만 전달된 항목이 없으면 기본값을 사용해야 할 경우, 구성 프로바이더가 없더라도 오류가 발생하지 않으며 종속성은 선택 사항이 된다.

 

프로바이더가 선택적임을 나타내려면 @Optional() 생성자의 서명에 데코레이터를 사용한다.

import { Injectable, Optional, Inject } from '@nestjs/common';

@Injectable()
export class HttpService<T> {
  constructor(@Optional() @Inject('HTTP_OPTIONS') private httpClient: T) {}
}

위의 예에서 HTTP_OPTIONS 토큰을 사용하는 사용자 정의 공급자를 사용하고 있다. 다른 장에서 자세히 알아보겠다.

 

속성 기반 주입

공급자가 생성자 메서드를 통해 주입되므로 이제까지 다른 기술은 생성자 기반 주입이라고 한다. 매우 특정한 경우에 속성기반 주입이 사용될 수 있다. 예를 들어 최상위 클랙스가 하나 이상의 공급자에 의존하는 경우 최상위 클래스의 하위클래스의 생성자에서 super()를 호출하여 공급자를 끝까지 전달하는 것은 매우 불편하다. 이를 해결하려면 @Inject() 데코레이션으로 속성 수준에서 사용하면 된다.

import { Injectable, Inject } from '@nestjs/common';

@Injectable()
export class HttpService<T> {
  @Inject('HTTP_OPTIONS')
  private readonly httpClient: T;
}

 

프로바이더 등록

이제 CatsService 프로바이더를 정의했고 해당 서비스의 소비자인 CatsController 가 있으므로 의존성 주입을 수행할 수 있도록 Nest에 서비스를 동록해야한다. app.moduel.ts 파일을 열고 @Module 데코레이터 providers 배열에 CatsService를 추가한다.

import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class AppModule {}

이로서 Next는 CatsController 클래스의 종속성을 해결 할 수 있다.

 

현재까지의 디렉토리 구조은 다음과 같다.

  • src
    • cats
      • dto
        • create-cat.dto.ts
      • interfaces
        • cat.interface.ts
      • cats.controller.ts
      • cats.service.ts
    • app.module.ts
    • main.ts

수동 인스턴스화

지금까지 Nest가 종속성을 어떻게 자동화하여 처리 하는지 알아봤다.  특정 상황에서는 기본 제공 종속성 주입 시스템 외에 수동으로 공급자를 검색하거나 인스턴스화해야 할 수도 있다. 다른 장에서 설명하겠다.

'Backend(Framework) > NestJS 개요(공식문서 번역)' 카테고리의 다른 글

6. Exception filters  (0) 2023.11.17
5. Middleware  (1) 2023.11.16
4. Modules  (1) 2023.11.16
2. Controller  (0) 2023.11.05
1. NestJS 시작  (0) 2023.11.04
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유