nest 공식문서 Providers

송은우·2022년 3월 24일
0

Providers

Nest의 가장 기본적인 개념이며, 가장 기본적인 아이디어는 injected as dependency 라는 DI를 기본으로 함. Nest 공식문서 Provider이미지

Controller가 Http request를 처리하고, 복잡한 것들은 provider에게 위임한다.
provider는 class고, module에서 provider로 등록된 것 뿐이다.

SOLID원칙

  1. S(ingle Response principle)RP 한 클래스는 하나의 책임만 가져야 한다.
  2. O(pen/closed principle)CP 확장에는 열려 있으나 변경에는 닫혀 있어야 한다 제대로 동작하고 있는 원래 코드를 변경하지 않고도, 새 코드를 추가함으로써 기능 추가, 변경이 가능해야 한다. 새 코드 추가로 변경할 수 있다, 코드 추가 없이 기능을 확장하거나 변경할 수 있다.
  3. L(iskov substitution principle)SP 프로그램 객체는 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.class fruit extends apple같은 경우라면, apple의 인스턴스를 fruit의 인스턴스로 넘길 수 있다는 것과 유사합니다. 이 부분은 Open/closed principle과도 관련이 있습니다.
  4. I(nterface segregation principle)SP 인터 페이스 분리의 원칙. 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스보다 낫다. 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 내용이 있다. 대충 생각한다면 interface 에 value, function 같이 이름을 대충 짓는 그런 것들을 하지 말아라 라고 생각하면 될 것 같습니다.
  5. D(ependency inversion principle)IP 의존관계 역전의 원칙
    추상 =>구체 =>추상 => 구체 느낌으로 가야지, 구체=> 구체 순으로 가면 안 된다는 것입니다. 상위 모듈은 하위 모듈에 의존해서는 안 된다는 것과, 상위 모듈과 하위 모듈 모두 추상적으로 해야 한다는 점이 있습니다. 이것 역시 개방 폐쇠 원칙과 비슷하며, 상위=>하위 라고 했을 때 상위 클래스를 바꾸면, 하위 클래스가 제대로 동작하지 않는 경우가 발생하기에, 이를 문제 없이 변경하는 것을 위해 상위 => 추상=> 하위나, 추상=>상위,하위로 바꿔야 한다
    DI와 관련된 원칙이다. 여기서 Nest와의 공통점이 나온다

Provider로 다시 돌아가면

@Injectable() 데코레이터를 클래스 앞에 붙히게 됩니다. 그랬을 경우 metadata를 붙히고, CatService클래스를 Nest IOC에 의해 컨트롤 된다는 점이 있습니다.

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;
  }
}

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

CatService를 Controller의 constructor에 넣어줌으로써 컨트롤러에 등록하고 사용할 수 있다.

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();
  }
}

중요한 점은 private연산자로 처리한다는 것. 저렇게 축약하면, 선언과 멤버를 추가하는 과정을 알아서 해준다

Dependency Injection

Angular의 영향을 받음
dependency란 기능을 수행하는데 필요한 개체 또는 서비스
DI는 종속성을 생성하는 대신 외부 소스에 종속성을 요청하는 설계 패턴
Angular의 DI프레임워크는 인스턴스 생성 시 클래스에 종속성을 주입하는 방법으로 DI를 구현함. 이를 Nest가 정확하게 가져왔음

TS를 쓰기에, 그냥 type만을 이용해서 dependency를 관리해버림.
이때 Singleton 모델을 사용하는 것이 전제이기에 service 인스턴스를 생성하거나, 다른 곳에 생성된 것을 가져옴

Scope
Provider가 application과 동일한 lifetime 을 갖기에, application가 bootstrap 되자마자 모든 provider가 인스턴스화 되어야 한다. application 종료시 바로 종료 해야 한다.
단 injection scope라는 특수한 scope도 있다.

Inversion of Control
Nest 는 내장되어 있는 IoC container가 있고, 그 컨테이너가 provider들 간의 관계를 해결해 준다.
provider에는
1. plain value
2. classes
3. async,sync factories
같은 것들을 담을 수 있다.

Optional provider
반드시 resolve 되어야 되는 dependency가 아닌 경우 @Optional 를 붙힐 수 있다. 대표적인 것은 configuration object. default값이 있고, optional value가 있다면 그 값으로 대체하는 경우

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

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

Property based injection
대부분 constructor based injection을 사용하지만, property-based injection을 쓰는 경우가 좋은 상황이 나온다.

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

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

top-level 클래스가 provider가 있을 경우, super을 통해 하는 것을 권장하지 않는다. 이때 Inject 키워드를 property level에서 쓸 수 있다.
클래스가 다른 provider를 extend하지 않는다면 constructor-based만 사용하기를 권장함

Provider Registration
Module에 providers 부분에 등록할 수 있다.

profile
학생의 마음가짐으로 최선을 다하자

0개의 댓글

관련 채용 정보