Providers

Providers

공급자는 Nest의 기본 개념입니다. 많은 기본 Nest 클래스는 서비스, 저장소, 팩토리, 헬퍼 등 공급자로 취급될 수 있습니다. 공급자의 주요 아이디어는 의존성을 주입 할 수 있다는 것입니다. 즉, 개체가 서로 다양한 관계를 만들 수 있으며 개체의 "배선"기능을 Nest 런타임 시스템에 크게 위임 할 수 있습니다. 공급자는 단순히 @Injectable()데코레이터로 주석이 달린 클래스입니다.

이전 장에서 우리는 간단한 CatsController를 만들었습니다. 컨트롤러는 HTTP 요청을 처리하고 더 복잡한 작업을 공급자에게 위임해야 합니다. 공급자는 클래스 선언 앞에 @Injectable() 데코레이터가 있는 일반 JavaScript 클래스입니다.

info 힌트 Nest를 사용하면 좀 더 다양한 방법으로 종속성을 디자인하고 구성 할 수 있으므로 SOLID 원칙을 따르는 것이 좋습니다.

Services

간단한 CatsService를 만들어 봅시다. 이 서비스는 데이터 저장 및 검색을 담당하며 CatsController에서 사용하도록 설계되었으므로 공급자로 정의하는 것이 좋습니다. 따라서 클래스를 @Injectable()으로 장식합니다.

@@filename(cats.service)
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;
  }
}
@@switch
import { Injectable } from '@nestjs/common';

@Injectable()
export class CatsService {
  constructor() {
    this.cats = [];
  }

  create(cat) {
    this.cats.push(cat);
  }

  findAll() {
    return this.cats;
  }
}

info 힌트 CLI를 사용하여 서비스를 만들려면 간단히 $nest g service cats 명령을 실행하십시오.

우리의 CatsService는 하나의 속성과 두 개의 메소드를 가진 기본 클래스입니다. 유일한 새로운 기능은@Injectable() 데코레이터를 사용한다는 것입니다. @Injectable() 데코레이터는 메타 데이터를 첨부하여 이 클래스가 Nest 공급자라는 것을 Nest에게 알려줍니다. 그건 그렇고, 이 예제는 Cat 인터페이스도 사용하는데, 아마도 다음과 같이 보일 것입니다:

export interface Cat {
  name: string;
  age: number;
  breed: string;
}

Cat를 검색하는 서비스 클래스가 생겼으니 CatsController 안에서 사용하자:

@@filename(cats.controller)
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 readonly catsService: CatsService) {}

  @Post()
  async create(@Body() createCatDto: CreateCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}
@@switch
import { Controller, Get, Post, Body, Bind, Dependencies } from '@nestjs/common';
import { CatsService } from './cats.service';

@Controller('cats')
@Dependencies(CatsService)
export class CatsController {
  constructor(catsService) {
    this.catsService = catsService;
  }

  @Post()
  @Bind(Body())
  async create(createCatDto) {
    this.catsService.create(createCatDto);
  }

  @Get()
  async findAll() {
    return this.catsService.findAll();
  }
}

CatsService는 클래스 생성자를 통해 주입됩니다. private readonly 구문의 사용에 주목하십시오. 이 속기는 우리가 동일한 위치에서 즉시 catsService 멤버를 선언하고 초기화 할 수있게 한다.

Dependency injection

Nest는 일반적으로 종속 주입으로 알려진 강력한 디자인 패턴을 중심으로 구축되었습니다. 공식 Angular 문서에서 이 개념에 대한 훌륭한 기사를 읽는 것이 좋습니다.

Nest의 TypeScript 기능 덕분에 종속성은 유형별로 해결되기 때문에 종속성을 관리하기가 매우 쉽습니다. 아래 예제에서 Nest는 CatsService의 인스턴스를 생성하고 반환함으로써 (또는 일반적인 경우 싱글 톤의 경우 이미 다른 곳에 요청 된 경우 기존 인스턴스를 반환하여) catsService를 해결합니다. 이 종속성은 해결되어 컨트롤러의 생성자에게 전달되거나 표시된 속성에 할당됩니다.

constructor(private readonly catsService: CatsService) {}

Scopes

공급자는 일반적으로 응용 프로그램 수명주기와 동기화 된 수명 ( 범위)을 갖습니다. 응용 프로그램이 부트 스트랩 될 때 모든 종속성을 해결해야 하므로 모든 공급자를 인스턴스화 해야 합니다. 마찬가지로 응용 프로그램이 종료되면 각 공급자가 삭제됩니다. 그러나 공급자의 수명을 요청 범위로 만드는 방법도 있습니다. 이러한 기술에 대한 자세한 내용은 여기를 참조하십시오.

Custom providers

Nest에는 공급자간 관계를 해결하는 기본 제공 제어 역전 ( "IoC") 컨테이너가 있습니다. 이 기능은 위에서 설명한 종속성 주입 기능의 기초가 되지만 실제로 지금까지 설명한 것보다 훨씬 강력합니다. @Injectable() 데코레이터는 빙산의 일각 일 뿐이며 공급자를 정의하는 유일한 방법은 아닙니다. 실제로 일반 값, 클래스 및 비동기 또는 동기 팩토리를 사용할 수 있습니다. 더 많은 예가 여기에 제공됩니다 .

Optional providers

때때로, 반드시 해결 될 필요가 없는 종속성이 있을 수 있습니다. 예를 들어 클래스는 구성 객체에 의존할 수 있지만 전달되지 않은 경우 기본값을 사용해야합니다. 이러한 경우 구성 공급자가 없으면 오류가 발생하지 않으므로 종속성이 선택 사항이됩니다.

공급자가 선택적임을 나타내려면 constructor 서명에 @Optional() 데코레이터를 사용하십시오.

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

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

위의 예에서 우리는 커스텀 제공자를 사용하고 있는데, 이것이 우리가 HTTP_OPTIONS 커스텀 토큰을 포함하는 이유입니다. 이전 예제는 생성자에서 클래스를 통한 종속성을 나타내는 생성자 기반 주입을 보여줍니다. 사용자 지정 공급자 및 관련 토큰에 대한 자세한 내용은 여기를 참조하십시오.

Property-based injection

우리가 지금까지 사용한 기술은 생성자 메서드를 통해 공급자가 주입되므로 constuctor 기반 주입이라고 합니다. 매우 특정한 경우에는 속성 기반 주입이 유용 할 수 있습니다. 예를 들어 최상위 클래스가 하나 이상의 공급자에 의존하는 경우 생성자의 하위 클래스에서 super()를 호출하여 모든 공급자를 전달하는 것은 매우 지루할 수 있습니다. 이를 피하기 위해 속성 레벨에서 @Inject()데코레이터를 사용할 수 있습니다.

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

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

warning 경고 클래스가 다른 제공자를 확장하지 않는 경우 항상 생성자 기반 주입을 사용하는 것이 좋습니다.

Provider registration

이제 우리는 공급자 (CatsService)를 정의했고, 그 서비스의 소비자 (CatsController)를 가지고 있으므로, 주입을 수행할 수 있도록 Nest에 서비스를 등록해야 합니다. 모듈 파일 (app.module.ts)을 편집하고 서비스를 @Module() 데코레이터의 providers 배열에 추가하면 됩니다.

@@filename(app.module)
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 {}

Nest는 이제 CatsController 클래스의 의존성을 해결할 수 있습니다.

디렉토리 구조는 다음과 같습니다.

  • src

    • cats

      • dto

        • create-cat.dto.ts

      • interfaces

        • cat.interface.ts

      • cats.service.ts

      • cats.controller.ts

    • app.module.ts

    • main.ts

Last updated