Providers

์ •๋ฏผ๊ตยท2023๋…„ 9์›” 5์ผ
0

NestJS

๋ชฉ๋ก ๋ณด๊ธฐ
3/4

๐Ÿ“’Providers

ํ”„๋กœ๋ฐ”์ด๋”๋Š” Nest์˜ ํ•ต์‹ฌ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ๋งŽ์€ ๊ธฐ๋ณธ Nest ํด๋ž˜์Šค๋“ค์€ services, repositories, factories, helpers ๋“ฑ์˜ provider๋กœ ์ทจ๊ธ‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

provider์˜ ํ•ต์‹ฌ์€ ์˜์กด์„ฑ์œผ๋กœ ์ฃผ์ž…๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.(๊ฐ์ฒด๋“ค์ด ์„œ๋กœ ์˜์กดํ•˜๋ฉฐ ๋‹ค์–‘ํ•œ ๊ด€๊ณ„๋ฅผ ํ˜•์„ฑํ•จ), ๊ทธ๋ฆฌ๊ณ  ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๋งบ๋Š” ์ž‘์—…(์—ฐ๊ฒฐ)์€ Nest ๋Ÿฐํƒ€์ž„ ์‹œ์Šคํ…œ์— ์œ„์ž„ํ•ฉ๋‹ˆ๋‹ค.

์ปจํŠธ๋กค๋Ÿฌ๋Š” HTTP ์š”์ฒญ์„ ๋ฐ›๊ณ  ๋ณต์žกํ•œ ํ•ต์‹ฌ ๋กœ์ง๋“ค์„ ํ”„๋กœ๋ฐ”์ด๋ฉ๊ฒŒ ์œ„์ž„ํ•˜๋Š” ์ผ์„ ์ „๋‹ดํ•ฉ๋‹ˆ๋‹ค.
ํ”„๋กœ๋ฐ”์ด๋”๋Š” ์ˆœ์ˆ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํด๋ž˜์Šค๋กœ module์— provider๋กœ ์„ ์–ธ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Nest๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ์ ์ธ ๋ฐฉ์‹์œผ๋กœ ์˜์กด์„ฑ์„ ์„ค๊ณ„ํ•˜๊ณ  ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— SOLID ์›์น™์„ ๋”ฐ๋ฅด๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

โœ”๏ธServices

$ nest g service <service class name>
์œ„์™€ ๊ฐ™์€ nest cli ๋ช…๋ น์–ด๋กœ ๊ฐ„๋‹จํ•˜๊ฒŒ service๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

์œ„์˜ CatsService ํ•˜๋‚˜์˜ ํ”„๋กœํผํ‹ฐ์™€ ๋‘ ๊ฐœ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ๊ฐ„๋‹จํ•œ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค.

@Injectable() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” CatsService๊ฐ€ Nest IoC ์ปจํ…Œ์ด๋„ˆ์— ์˜ํ•ด ๊ด€๋ฆฌ๋˜๋Š” ํด๋ž˜์Šค๋ผ๋Š” ์ •๋ณด๋ฅผ ์ฒจ๋ถ€ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

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

์œ„๋Š” Cat ์ธํ„ฐํŽ˜์ด์Šค ์ž…๋‹ˆ๋‹ค.

// 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 ์™€ Cat ์ธํ„ฐํŽ˜์ด์Šค๋„ ์ƒ์„ฑํ–ˆ์œผ๋‹ˆ ์ด์ œ CatsService๋ฅผ CatsController ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์ œ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์œ„ CatsController์—์„œ CatsService๋Š” ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์œ„์ฒ˜๋Ÿผ private ๋‹จ์ถ• ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. TS ๋ฌธ๋ฒ•์„ ํ™•์ธํ•˜์„ธ์š”

โœ”๏ธDependency Injection

Nest๋Š” DI๋กœ ์•Œ๋ ค์ง„ ๊ฐ•๋ ฅํ•œ ๋””์ž์ธ ํŒจํ„ด์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ตฌ์ถ•๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

constructor(private catsService: CatsService) {}

catsService๋Š” ์ƒ์„ฑ๋˜์–ด ๋ฐ˜ํ™˜๋œ CatsService์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹น๋ฐ›์Šต๋‹ˆ๋‹ค.(์ผ๋ฐ˜์ ์ธ ์‹ฑ๊ธ€ํ†ค์˜ ๊ฒฝ์šฐ์—๋Š” ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹น๋ฐ›์Šต๋‹ˆ๋‹ค.)

โœ”๏ธScopes

ํ”„๋กœ๋ฐ”์ด๋”๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ˆ˜๋ช… ์ฃผ๊ธฐ์™€ ๋™๊ธฐํ™”๋œ scope(๋ผ์ดํ”„ํƒ€์ž„)์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ๋  ๋•Œ ๋ชจ๋“  ์˜์กด์„ฑ์ด ํ•ด๊ฒฐ๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  ํ”„๋กœ๋ฐ”์ด๋”๋“ค์€ ์ธ์Šคํ„ด์Šคํ™”๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋™์ผํ•˜๊ฒŒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒ๋  ๋•Œ ๋ชจ๋“  ํ”„๋กœ๋ฐ”์ด๋”๋“ค ๋˜ํ•œ ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๋ฐ”์ด๋”์˜ ๋ผ์ดํ”„ํƒ€์ž„์„ request-sceoped๋กœ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. injection scopes

โœ”๏ธCustom providers

Nest๋Š” ๋นŒํŠธ์ธ IoC ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. IoC ์ปจํ…Œ์ด๋„ˆ๋Š” ์˜์กด์„ฑ ์ฃผ์ž… ๊ธฐ๋Šฅ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ”„๋กœ๋ฐ”์ด๋” ๊ฐ„์˜ ๊ด€๊ณ„, ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค, ๋‹จ์ˆœ ๊ฐ’, ํด๋ž˜์Šค, ๋น„๋™๊ธฐ ๋˜๋Š” ๋™๊ธฐ ํŒฉํ† ๋ฆฌ๋“ค์„ ํ”„๋กœ๋ฐ”์ด๋”๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

custom providers

โœ”๏ธOptional providers

๋ฐ˜๋“œ์‹œ ์˜์กด์„ฑ ์ฃผ์ž…์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ์—๋Š” ์ƒ์„ฑ์ž ์‹œ๊ทธ๋‹ˆ์ฒ˜์— @Optional ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ ํƒ์  ํ”„๋กœ๋ฐ”์ด๋”์ž„์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค๊ฐ€ ๊ตฌ์„ฑ ๊ฐ์ฒด์— ์˜์กดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ „๋‹ฌ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ๋ฐ”์ด๋”์˜ ๋ถ€์žฌ๋กœ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค.

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

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

์œ„์˜ ์˜ˆ์—์„œ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ์ด ๋•Œ๋ฌธ์— HTTP_OPTIONS ์‚ฌ์šฉ์ž ์ •์˜ ํ† ํฐ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ „ ์˜ˆ์ œ๋“ค์€ ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ ์ฃผ์ž…์„ ๋ณด์—ฌ์ฃผ์—ˆ๋Š”๋ฐ, ์ด๋Š” ์ƒ์„ฑ์ž ์•ˆ์—์„œ ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜ ํ”„๋กœ๋ฐ”์ด๋”์™€ ๊ทธ๋“ค๊ณผ ๊ด€๋ จ๋œ ํ† ํฐ์— ๋Œ€ํ•ด ๋” ์ž์„ธํ•œ ์ •๋ณด๋Š” ๋‹ค์Œ์„ ์ฐธ์กฐํ•˜์„ธ์š”

custom providers

โœ”๏ธProperty-based injection

์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณธ ์˜์กด์„ฑ ์ฃผ์ž…์€ ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ ์ฃผ์ž…(constructor-based injection)์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ํ”„๋กœ๋ฐ”์ด๋”๊ฐ€ ์ƒ์„ฑ์ž ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์†์„ฑ ๊ธฐ๋ฐ˜ ์ฃผ์ž…(property-based injection)์ด ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ตœ์ƒ์œ„ ํด๋ž˜์Šค๊ฐ€ ํ•˜๋‚˜ ์ด์ƒ์˜ ํ”„๋กœ๋ฐ”์ด๋”์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ,

ํ•˜์œ„ ํด๋ž˜์Šค์—์„œ super()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ๋ชจ๋“  ์˜์กด์„ฑ๋“ค์„ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์€ ๋ฒˆ๊ฑฐ๋กœ์šด ์ผ์ž…๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ผ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ํ”„๋กœํผํ‹ฐ ๋ ˆ๋ฒจ์—์„œ @Inject() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

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

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

๋งŒ์•ฝ ์•„๋ฌด ํด๋ž˜์Šค๋„ ํ™•์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค.

โœ”๏ธProvider registration

// app.module.ts
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 {}

ํ”„๋กœ๋ฐ”์ด๋”์ธ CatsService์™€ ์„œ๋น„์Šค์˜ consumer CatsController ๋ฅผ ์ •์˜ํ•˜์˜€์œผ๋‹ˆ๊นŒ, Nest์— ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ์˜์กด์„ฑ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ app.module.ts๋ฅผ ์œ„์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์—ฌ @Module ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์— CatsService๋ฅผ ํ”„๋กœ๋ฐ”์ด๋”์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ Nest๋Š” CatsController ํด๋ž˜์Šค์˜ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โœ”๏ธ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

โœ”๏ธManual instantiation

ํŠน์ • ์ƒํ™ฉ์—์„œ๋Š” ๋‚ด์žฅ๋œ ์˜์กด์„ฑ ์ฃผ์ž… ์‹œ์Šคํ…œ์„ ๋ฒ—์–ด๋‚˜์„œ ์ˆ˜๋™์œผ๋กœ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ฑฐ๋‚˜ ์ธ์Šคํ„ด์Šคํ™” ํ•ด์•ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๋™์ ์œผ๋กœ ์ธ์Šคํ„ด์Šคํ™” ํ•˜๋ ค๋ฉด Module ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. Module reference

bootstrap() ํ•จ์ˆ˜ ์•ˆ์—์„œ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” Standalone application ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š” Standalone application

profile
๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž

0๊ฐœ์˜ ๋Œ“๊ธ€