Nest의 가장 기본적인 개념이며, 가장 기본적인 아이디어는 injected as dependency 라는 DI를 기본으로 함.
Controller가 Http request를 처리하고, 복잡한 것들은 provider에게 위임한다.
provider는 class고, module에서 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연산자로 처리한다는 것. 저렇게 축약하면, 선언과 멤버를 추가하는 과정을 알아서 해준다
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 부분에 등록할 수 있다.