dev_writer 2025. 7. 5. 17:25

ํ”„๋กœ๋ฐ”์ด๋” (Providers)

 

Nest์—์„œ ํ”„๋กœ๋ฐ”์ด๋” (Provider)๋Š” ํ•ต์‹ฌ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค. ์„œ๋น„์Šค, ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ, ํŒฉํ† ๋ฆฌ, ํ—ฌํผ์™€ ๊ฐ™์€ ๊ธฐ๋ณธ Nest ํด๋ž˜์Šค ๋Œ€๋ถ€๋ถ„์€ ํ”„๋กœ๋ฐ”์ด๋”๋กœ ์ทจ๊ธ‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋ฐ”์ด๋”์˜ ํ•ต์‹ฌ ์•„์ด๋””์–ด๋Š” ์˜์กด์„ฑ์œผ๋กœ ์ฃผ์ž…๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋“ค ๊ฐ„์— ๋‹ค์–‘ํ•œ ๊ด€๊ณ„๋ฅผ ํ˜•์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฐ์ฒด๋“ค์„ ์—ฐ๊ฒฐ(wiring) ํ•˜๋Š” ์ž‘์—…์€ ๋Œ€๋ถ€๋ถ„ Nest์˜ ๋Ÿฐํƒ€์ž„ ์‹œ์Šคํ…œ์ด ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

 

์ด์ „ ์žฅ์—์„œ๋Š” ๊ฐ„๋‹จํ•œ CatsController๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ์ปจํŠธ๋กค๋Ÿฌ๋Š” HTTP ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋” ๋ณต์žกํ•œ ์ž‘์—…์€ ํ”„๋กœ๋ฐ”์ด๋”์—๊ฒŒ ์œ„์ž„ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋ฐ”์ด๋”๋Š” NestJS ๋ชจ๋“ˆ์—์„œ ํ”„๋กœ๋ฐ”์ด๋”๋กœ ์„ ์–ธ๋œ ์ผ๋ฐ˜ JavaScript ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ชจ๋“ˆ (Modules) ์žฅ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

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

์„œ๋น„์Šค

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

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() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์ž…๋‹ˆ๋‹ค. ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํด๋ž˜์Šค์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ถ€์—ฌํ•˜์—ฌ, Nest์˜ IoC ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ด ํด๋ž˜์Šค๋ฅผ ์˜์กด์„ฑ ์ฃผ์ž…์ด ๊ฐ€๋Šฅํ•œ ๊ด€๋ฆฌ ๋Œ€์ƒ์œผ๋กœ ์ธ์‹ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ ์ด ์˜ˆ์ œ๋Š” Cat์ด๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํ˜•ํƒœ์ผ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค:

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

 

์ด์ œ ๊ณ ์–‘์ด ์ •๋ณด๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ์„œ๋น„์Šค ํด๋ž˜์Šค๊ฐ€ ์ค€๋น„๋˜์—ˆ์œผ๋‹ˆ, ์ด๋ฅผ CatsController ์•ˆ์—์„œ ์‚ฌ์šฉํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค:

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๋Š” ํด๋ž˜์Šค ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•  ์ ์€ private ํ‚ค์›Œ๋“œ์˜ ์‚ฌ์šฉ์ž…๋‹ˆ๋‹ค. ์ด ์ถ•์•ฝํ˜• ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด catsService ๋ฉค๋ฒ„๋ฅผ ํ•œ ์ค„์—์„œ ์„ ์–ธ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ๋™์‹œ์— ํ•  ์ˆ˜ ์žˆ์–ด ์ฝ”๋“œ๋ฅผ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜์กด์„ฑ ์ฃผ์ž…

Nest๋Š” ์˜์กด์„ฑ ์ฃผ์ž… (Dependency Injection, DI)์ด๋ผ๋Š” ๊ฐ•๋ ฅํ•œ ์„ค๊ณ„ ํŒจํ„ด์„ ์ค‘์‹ฌ์œผ๋กœ ๊ตฌ์ถ•๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ๋Š” Angular ๊ณต์‹ ๋ฌธ์„œ์˜ ํ›Œ๋ฅญํ•œ ๊ธ€์„ ์ฐธ๊ณ ํ•ด ๋ณด๋Š” ๊ฒƒ์„ ์ ๊ทน ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.

 

Nest์—์„œ๋Š” TypeScript์˜ ๊ธฐ๋Šฅ ๋•๋ถ„์— ์˜์กด์„ฑ ๊ด€๋ฆฌ๊ฐ€ ๋งค์šฐ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค. ์˜์กด์„ฑ์€ ํƒ€์ž… ๊ธฐ๋ฐ˜์œผ๋กœ ์ž๋™ ํ•ด๊ฒฐ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ์—์„œ๋Š”, Nest๊ฐ€ catsService ํƒ€์ž… ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ CatsService์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ (์‹ฑ๊ธ€ํ†ค์ผ ๊ฒฝ์šฐ ์ด๋ฏธ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉ), ์ด๋ฅผ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์ƒ์„ฑ์ž์— ์ฃผ์ž…ํ•ด ์ค๋‹ˆ๋‹ค. ๋˜๋Š” ์ง€์ •๋œ ํ”„๋กœํผํ‹ฐ์— ํ• ๋‹นํ•ด ์ค๋‹ˆ๋‹ค:

constructor(private catsService: CatsService) {}

์Šค์ฝ”ํ”„

ํ”„๋กœ๋ฐ”์ด๋”๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ƒ๋ช…์ฃผ๊ธฐ์™€ ์ผ์น˜ํ•˜๋Š” ์ˆ˜๋ช… (scope)์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ถ€ํŠธ์ŠคํŠธ๋žฉ๋  ๋•Œ, ๋ชจ๋“  ์˜์กด์„ฑ์ด ํ•ด๊ฒฐ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ์ด๋Š” ๊ณง ๋ชจ๋“  ํ”„๋กœ๋ฐ”์ด๋”๊ฐ€ ์ธ์Šคํ„ด์Šคํ™”๋œ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ข…๋ฃŒ๋˜๋ฉด ๋ชจ๋“  ํ”„๋กœ๋ฐ”์ด๋”๋„ ์†Œ๋ฉธ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์š”์ฒญ ๋‹จ์œ„ (request-scoped)๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ํ”„๋กœ๋ฐ”์ด๋”์˜ ์ˆ˜๋ช…์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด๊ฐ€ ์•„๋‹Œ ํŠน์ • ์š”์ฒญ์— ํ•œ์ •๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ธฐ๋ฒ•์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ Injection Scopes ์žฅ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ปค์Šคํ…€ ํ”„๋กœ๋ฐ”์ด๋”

Nest์—๋Š” ์ œ์–ด์˜ ์—ญ์ „ (Inversion of Control, IoC) ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด, ํ”„๋กœ๋ฐ”์ด๋” ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์€ ์˜์กด์„ฑ ์ฃผ์ž…์˜ ๊ธฐ๋ฐ˜์ด ๋˜๋ฉฐ, ์ง€๊ธˆ๊นŒ์ง€ ์„ค๋ช…ํ•œ ๊ฒƒ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

Nest์—์„œ๋Š” ๋‹ค์–‘ํ•œ ๋ฐฉ์‹์œผ๋กœ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋‹จ์ˆœ ๊ฐ’ (value), ํด๋ž˜์Šค (class), ๋น„๋™๊ธฐ/๋™๊ธฐ ํŒฉํ† ๋ฆฌ (async/sync factory)๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ๋ฐ”์ด๋” ์ •์˜ ๋ฐฉ์‹์— ๋Œ€ํ•œ ๋” ๋งŽ์€ ์˜ˆ์ œ๋Š” Dependency Injection ์žฅ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ ํƒ์  ํ”„๋กœ๋ฐ”์ด๋”

๋•Œ๋•Œ๋กœ ๋ชจ๋“  ์˜์กด์„ฑ์ด ๋ฐ˜๋“œ์‹œ ํ•ด๊ฒฐ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํด๋ž˜์Šค๊ฐ€ ์„ค์ • ๊ฐ์ฒด์— ์˜์กดํ•˜์ง€๋งŒ ํ•ด๋‹น ์„ค์ •์ด ์ œ๊ณต๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ๊ฐ’์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๊ณ  ์‹ถ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น ์˜์กด์„ฑ์€ ์„ ํƒ์  (optional)์œผ๋กœ ๊ฐ„์ฃผ๋˜๋ฉฐ, ์„ค์ • ํ”„๋กœ๋ฐ”์ด๋”๊ฐ€ ์—†๋”๋ผ๋„ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ์˜์กด์„ฑ์„ ์„ ํƒ์ ์œผ๋กœ ํ‘œ์‹œํ•˜๋ ค๋ฉด ์ƒ์„ฑ์ž ์‹œ๊ทธ๋‹ˆ์ฒ˜์—์„œ @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 ์žฅ์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.

์†์„ฑ ๊ธฐ๋ฐ˜ ์ฃผ์ž…

์ง€๊ธˆ๊นŒ์ง€ ์‚ฌ์šฉํ•œ ๋ฐฉ์‹์€ ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ ์ฃผ์ž… (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;
}
๊ฒฝ๊ณ 
ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์ข‹์Šต๋‹ˆ๋‹ค. ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์–ด๋–ค ์˜์กด์„ฑ์ด ํ•„์š”ํ•œ์ง€ ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚˜๋ฏ€๋กœ, @Inject๋กœ ์†์„ฑ์— ์ฃผ์ž…ํ•˜๋Š” ๋ฐฉ์‹๋ณด๋‹ค ๊ฐ€๋…์„ฑ ๋ฐ ์ฝ”๋“œ ์ดํ•ด๋„ ์ธก๋ฉด์—์„œ ์šฐ์ˆ˜ํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๋ฐ”์ด๋” ๋“ฑ๋ก

CatsService๋ผ๋Š” ํ”„๋กœ๋ฐ”์ด๋”์™€ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” CatsController๋ผ๋Š” ์†Œ๋น„์ž๋ฅผ ์ •์˜ํ–ˆ์œผ๋ฏ€๋กœ, ์ด์ œ Nest์— ์ด ์„œ๋น„์Šค๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์•ผ Nest๊ฐ€ ์˜์กด์„ฑ์„ ํ•ด๊ฒฐํ•˜๊ณ  ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด app.module.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 {}

 

์ด์ œ Nest๋Š” CatsController ํด๋ž˜์Šค์˜ ์˜์กด์„ฑ์„ ์ •์ƒ์ ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

ํ˜„์žฌ๊นŒ์ง€์˜ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค:

src/
โ”œโ”€โ”€ cats/
โ”‚   โ”œโ”€โ”€ dto/
โ”‚   โ”‚   โ””โ”€โ”€ create-cat.dto.ts
โ”‚   โ”œโ”€โ”€ interfaces/
โ”‚   โ”‚   โ””โ”€โ”€ cat.interface.ts
โ”‚   โ”œโ”€โ”€ cats.controller.ts
โ”‚   โ””โ”€โ”€ cats.service.ts
โ”œโ”€โ”€ app.module.ts
โ””โ”€โ”€ main.ts

์ˆ˜๋™ ์„ค์น˜

์ง€๊ธˆ๊นŒ์ง€ ์šฐ๋ฆฌ๋Š” Nest๊ฐ€ ์˜์กด์„ฑ ํ•ด๊ฒฐ์˜ ๋Œ€๋ถ€๋ถ„์„ ์ž๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฒฝ์šฐ์— ๋”ฐ๋ผ Nest์˜ ๋‚ด์žฅ ์˜์กด์„ฑ ์ฃผ์ž… ์‹œ์Šคํ…œ์„ ๋ฒ—์–ด๋‚˜, ์ง์ ‘ ํ”„๋กœ๋ฐ”์ด๋” ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๋™์ ์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์— ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๊ธฐ๋ฒ•์„ ๊ฐ„๋‹จํžˆ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค:

  • ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๋ฅผ ์กฐํšŒํ•˜๊ฑฐ๋‚˜ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๋™์ ์œผ๋กœ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๋ ค๋ฉด ๋ชจ๋“ˆ ์ฐธ์กฐ (Module reference)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ถ€ํŠธ์ŠคํŠธ๋žฉ ์‹œ์ ์— ํ”„๋กœ๋ฐ”์ด๋” (์˜ˆ: ์„ค์ • ์„œ๋น„์Šค ๋“ฑ)๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด, bootstrap() ํ•จ์ˆ˜ ๋‚ด์—์„œ ์ฃผ์ž…๋ฐ›๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋…๋ฆฝํ˜• ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ตฌ์„ฑ ์‹œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. (์ž์„ธํ•œ ๋‚ด์šฉ์€ Standalone applications ์žฅ ์ฐธ๊ณ )

๋ชจ๋“ˆ (Modules)

๋ชจ๋“ˆ (Module)์€ @Module() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๊ฐ€ ๋ถ™์€ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” Nest๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๊ตฌ์กฐ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  Nest ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ตœ์†Œ ํ•˜๋‚˜์˜ ๋ชจ๋“ˆ, ์ฆ‰ ๋ฃจํŠธ ๋ชจ๋“ˆ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ด๋Š” Nest๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ทธ๋ž˜ํ”„๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ์‹œ์ž‘์  ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ทธ๋ž˜ํ”„๋Š” ๋ชจ๋“ˆ๊ณผ ํ”„๋กœ๋ฐ”์ด๋” ๊ฐ„์˜ ๊ด€๊ณ„ ๋ฐ ์˜์กด์„ฑ์„ Nest๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์†Œ๊ทœ๋ชจ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ๋ฃจํŠธ ๋ชจ๋“ˆ ํ•˜๋‚˜๋งŒ์œผ๋กœ ์ถฉ๋ถ„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Nest์—์„œ๋Š” ๋ชจ๋“ˆ ๋‹จ์œ„์˜ ๊ตฌ์„ฑ์ด ๊ถŒ์žฅ๋˜๋ฉฐ, ๋Œ€๋ถ€๋ถ„์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ๊ฐ ๋ชจ๋“ˆ์€ ๋ฐ€์ ‘ํ•˜๊ฒŒ ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ๋“ค์„ ์บก์Аํ™”ํ•ฉ๋‹ˆ๋‹ค.

 

@Module() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋ฅผ ์ธ์ž๋กœ ๋ฐ›์œผ๋ฉฐ, ์ด ๊ฐ์ฒด๋Š” ๋ชจ๋“ˆ์„ ๊ตฌ์„ฑํ•˜๋Š” ๋‹ค์–‘ํ•œ ์†์„ฑ๋“ค์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.

providers ์ด ๋ชจ๋“ˆ์—์„œ Nest ์ธ์ ํ„ฐ์— ์˜ํ•ด ์ธ์Šคํ„ด์Šคํ™” ๋  ํ”„๋กœ๋ฐ”์ด๋”๋“ค (๊ทธ๋ฆฌ๊ณ  ์ตœ์†Œํ•œ ์ด ๋ชจ๋“ˆ ๋‚ด์—์„œ ๊ณต์œ ๋  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค)
controllers ์ด ๋ชจ๋“ˆ์— ์ •์˜๋œ ์ปจํŠธ๋กค๋Ÿฌ ์ง‘ํ•ฉ, Nest๊ฐ€ ์ด๋“ค์„ ์ธ์Šคํ„ด์Šคํ™” ํ•ด์•ผ ํ•จ
imports ์ด ๋ชจ๋“ˆ์—์„œ ํ•„์š”ํ•œ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ๋‚ด๋ณด๋‚ด๋Š” (import) ์™ธ๋ถ€ ๋ชจ๋“ˆ๋“ค ๋ชฉ๋ก
exports ์ด ๋ชจ๋“ˆ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋“ค์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋‚ด๋ณด๋‚ผ (export) ํ”„๋กœ๋ฐ”์ด๋”์˜ ์ผ๋ถ€ - ํ”„๋กœ๋ฐ”์ด๋” ์ž์ฒด ๋˜๋Š” ํ•ด๋‹น ํ† ํฐ (provide ๊ฐ’) ๋งŒ์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Œ

 

๋ชจ๋“ˆ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์บก์Аํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ํ˜„์žฌ ๋ชจ๋“ˆ์˜ ์ผ๋ถ€์ด๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ๋ช…์‹œ์ ์œผ๋กœ export ๋œ ํ”„๋กœ๋ฐ”์ด๋”๋งŒ ์ฃผ์ž…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋“ˆ์—์„œ export ๋œ ํ”„๋กœ๋ฐ”์ด๋”๋Š” ํ•ด๋‹น ๋ชจ๋“ˆ์˜ ๊ณต๊ฐœ ์ธํ„ฐํŽ˜์ด์Šค (API) ์—ญํ• ์„ ํ•˜๋ฉฐ, ๋‹ค๋ฅธ ๋ชจ๋“ˆ์ด ์ด ๋ชจ๋“ˆ๊ณผ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋Šฅ ๋ชจ๋“ˆ (Feature Modules)

์˜ˆ์ œ์—์„œ CatsController์™€ CatsService๋Š” ๋ฐ€์ ‘ํ•œ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง€๋ฉฐ ๋™์ผํ•œ ๋„๋ฉ”์ธ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๋‘˜์„ ํ•˜๋‚˜์˜ ๊ธฐ๋Šฅ ๋ชจ๋“ˆ (feature module)๋กœ ๋ฌถ๋Š” ๊ฒƒ์ด ํƒ€๋‹นํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋Šฅ ๋ชจ๋“ˆ์€ ํŠน์ • ๊ธฐ๋Šฅ๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ์กฐ์งํ™”ํ•˜๋ฉฐ, ๋ช…ํ™•ํ•œ ๊ฒฝ๊ณ„์™€ ๋” ๋‚˜์€ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด๋‚˜ ํŒ€ ๊ทœ๋ชจ๊ฐ€ ์ปค์งˆ์ˆ˜๋ก ๋”์šฑ ์ค‘์š”ํ•ด์ง€๋ฉฐ, SOLID ์›์น™๊ณผ๋„ ์ž˜ ๋ถ€ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

 

์ด์ œ CatsModule์„ ์ƒ์„ฑํ•˜์—ฌ ์ปจํŠธ๋กค๋Ÿฌ์™€ ์„œ๋น„์Šค๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฌถ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {}
ํžŒํŠธ
CLI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“ˆ์„ ์ƒ์„ฑํ•˜๋ ค๋ฉด, ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค: nest g module cats

 

์œ„์—์„œ๋Š” cats.module.ts ํŒŒ์ผ์—์„œ CatsModule์„ ์ •์˜ํ•˜๊ณ , ์ด ๋ชจ๋“ˆ๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ํŒŒ์ผ์„ cats ๋””๋ ‰ํ„ฐ๋ฆฌ๋กœ ์ด๋™์‹œ์ผฐ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด์•ผ ํ•  ์ผ์€, ์ด CatsModule์„ ๋ฃจํŠธ ๋ชจ๋“ˆ (AppModule)์— import ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. AppModule์€ app.module.ts ํŒŒ์ผ์— ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule {}

 

ํ˜„์žฌ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

src/
โ”œโ”€โ”€ cats/
โ”‚   โ”œโ”€โ”€ dto/
โ”‚   โ”‚   โ””โ”€โ”€ create-cat.dto.ts
โ”‚   โ”œโ”€โ”€ interfaces/
โ”‚   โ”‚   โ””โ”€โ”€ cat.interface.ts
โ”‚   โ”œโ”€โ”€ cats.controller.ts
โ”‚   โ”œโ”€โ”€ cats.module.ts
โ”‚   โ””โ”€โ”€ cats.service.ts
โ”œโ”€โ”€ app.module.ts
โ””โ”€โ”€ main.ts

๊ณต์œ  ๋ชจ๋“ˆ

Nest์—์„œ๋Š” ๋ชจ๋“ˆ์ด ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค (singleton)์œผ๋กœ ๋™์ž‘ํ•˜๋ฏ€๋กœ, ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ ๊ฐ„์— ๋™์ผํ•œ ํ”„๋กœ๋ฐ”์ด๋” ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณ„๋‹ค๋ฅธ ์„ค์ • ์—†์ด ์‰ฝ๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ๋ชจ๋“ˆ์€ ์ž๋™์ ์œผ๋กœ ๊ณต์œ  ๋ชจ๋“ˆ (shared module)์ž…๋‹ˆ๋‹ค. ํ•œ ๋ฒˆ ์ƒ์„ฑ๋œ ๋ชจ๋“  ๋ชจ๋“ˆ์€ ๋‹ค๋ฅธ ์–ด๋–ค ๋ชจ๋“ˆ์—์„œ๋„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, CatsService ์ธ์Šคํ„ด์Šค๋ฅผ ์—ฌ๋Ÿฌ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์—์„œ ๊ณต์œ ํ•˜๊ณ ์ž ํ•œ๋‹ค๋ฉด, ๋จผ์ € ํ•ด๋‹น ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ exports ๋ฐฐ์—ด์— ์ถ”๊ฐ€ํ•˜์—ฌ export ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค:

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

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

 

์ด์ œ CatsModule์„ import ํ•˜๋Š” ์–ด๋А ๋ชจ๋“ˆ์—์„œ๋“  CatsService์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด ์„œ๋น„์Šค๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ๋ชจ๋“ˆ๊ณผ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๋งŒ์•ฝ CatsService๋ฅผ ํ•„์š”ํ•œ ๊ฐ ๋ชจ๋“ˆ์— ์ง์ ‘ ๋“ฑ๋กํ•œ๋‹ค๋ฉด, ์„œ๋น„์Šค๋Š” ์ž‘๋™ํ•˜๊ธด ํ•˜์ง€๋งŒ ๋ชจ๋“ˆ๋งˆ๋‹ค ๋ณ„๋„์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๋˜๋ฉด ๊ฐ™์€ ์„œ๋น„์Šค๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜์–ด ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋Š” ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ ์ƒํƒœ ๋ถˆ์ผ์น˜์™€ ๊ฐ™์€ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

CatsService๋ฅผ CatsModule์ด๋ผ๋Š” ๋ชจ๋“ˆ ์•ˆ์— ์บก์Аํ™”ํ•˜๊ณ  exports๋ฅผ ํ†ตํ•ด ์™ธ๋ถ€๋กœ ๋‚ด๋ณด๋ƒ„์œผ๋กœ์จ, ์ด ๋ชจ๋“ˆ์„ ๊ฐ€์ ธ๋‹ค ์“ฐ๋Š” ๋ชจ๋“  ๊ณณ์—์„œ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์„ ์ค„์ด๊ณ , ๋ชจ๋“ˆ ๊ฐ„ ๋™์ž‘์„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๋ฉฐ, ๊ณต์œ  ์ƒํƒœ๋‚˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์ผ๊ด€๋˜๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

 

์ด๋Š” NestJS์™€ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๋ชจ๋“ˆํ™”์™€ ์˜์กด์„ฑ ์ฃผ์ž… (DI)์ด ์ œ๊ณตํ•˜๋Š” ํ•ต์‹ฌ ์žฅ์  ์ค‘ ํ•˜๋‚˜๋กœ, ์„œ๋น„์Šค๋“ค์„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ๊ฑธ์ณ ํšจ์œจ์ ์œผ๋กœ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ค๋‹ˆ๋‹ค.

๋ชจ๋“ˆ ์žฌ ๋‚ด๋ณด๋‚ด๊ธฐ (Module re-exporting)

์•ž์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ, ๋ชจ๋“ˆ์€ ๋‚ด๋ถ€์˜ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ export ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”๋ถˆ์–ด, import ํ•œ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์„ ๋‹ค์‹œ export ํ•˜์—ฌ ์™ธ๋ถ€๋กœ ์ „๋‹ฌํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด CoreModule์ด CommonModule์„ import ํ•˜๊ณ  ๋™์‹œ์— export ํ•˜๋ฉด, CoreModule์„ import ํ•˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋“ค์—์„œ๋„ ๋ณ„๋„๋กœ CommonModule์„ import ํ•˜์ง€ ์•Š์•„๋„ ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

@Module({
  imports: [CommonModule],
  exports: [CommonModule],
})
export class CoreModule {}

์˜์กด์„ฑ ์ฃผ์ž…

๋ชจ๋“ˆ ํด๋ž˜์Šค์—์„œ๋„ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ฃผ์ž…๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค (์˜ˆ: ์„ค์ • ๊ฐ’์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด).

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

@Module({
  controllers: [CatsController],
  providers: [CatsService],
})
export class CatsModule {
  constructor(private catsService: CatsService) {}
}

 

ํ•˜์ง€๋งŒ ๋ชจ๋“ˆ ํด๋ž˜์Šค ์ž์ฒด๋Š” ์ˆœํ™˜ ์˜์กด์„ฑ (circular dependency) ๋•Œ๋ฌธ์— ํ”„๋กœ๋ฐ”์ด๋”๋กœ ์ฃผ์ž…๋  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค.

 

์ „์—ญ ๋ชจ๋“ˆ

์–ด๋””์—์„œ๋“  ๋™์ผํ•œ ๋ชจ๋“ˆ ์ง‘ํ•ฉ์„ ๋ฐ˜๋ณต์ ์œผ๋กœ import ํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ์ด๋Š” ๋ฒˆ๊ฑฐ๋กœ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Angular์™€๋Š” ๋‹ฌ๋ฆฌ, Nest์—์„œ๋Š” ํ”„๋กœ๋ฐ”์ด๋”๊ฐ€ ์ „์—ญ ๋ฒ”์œ„๊ฐ€ ์•„๋‹Œ ๋ชจ๋“ˆ ๋ฒ”์œ„์— ๋“ฑ๋ก๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, Nest์—์„œ๋Š” ์–ด๋–ค ๋ชจ๋“ˆ์˜ ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด, ๋จผ์ € ํ•ด๋‹น ๋ชจ๋“ˆ์„ import ํ•ด์•ผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ—ฌํผ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ๋“ฑ๊ณผ ๊ฐ™์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•˜๋Š” ํ”„๋กœ๋ฐ”์ด๋” ์ง‘ํ•ฉ์„ ์ œ๊ณตํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ํ•ด๋‹น ๋ชจ๋“ˆ์— @Global() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋ถ™์—ฌ ์ „์—ญ ๋ชจ๋“ˆ (Global Module)๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

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

 

@Global() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํ•ด๋‹น ๋ชจ๋“ˆ์„ ์ „์—ญ ๋ฒ”์œ„ (Global scope)๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ „์—ญ ๋ชจ๋“ˆ์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ฃจํŠธ ๋ชจ๋“ˆ์ด๋‚˜ ์ฝ”์–ด ๋ชจ๋“ˆ์—์„œ ๋‹จ ํ•œ ๋ฒˆ๋งŒ ๋“ฑ๋ก๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์œ„ ์˜ˆ์‹œ์—์„œ์ฒ˜๋Ÿผ CatsService๊ฐ€ ์ „์—ญ ๋ชจ๋“ˆ๋กœ ์ œ๊ณต๋˜๋ฉด, ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๋‹ค๋ฅธ ๋ชจ๋“ˆ๋“ค์€ CatsModule์„ imports ๋ฐฐ์—ด์— ๋ช…์‹œํ•  ํ•„์š” ์—†์ด ๋ฐ”๋กœ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํžŒํŠธ
๋ชจ๋“  ๊ฒƒ์„ ์ „์—ญ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•œ ์„ค๊ณ„ ๋ฐฉ์‹์ด ์•„๋‹™๋‹ˆ๋‹ค. ์ „์—ญ ๋ชจ๋“ˆ์€ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๋ฅผ ์ค„์ด๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ๋Š” imports ๋ฐฐ์—ด์„ ํ†ตํ•ด ๋ช…์‹œ์ ์œผ๋กœ ๋ชจ๋“ˆ์˜ API๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋ฐฉ์‹์ด ๊ตฌ์กฐ์ ์ด๊ณ  ์œ ์ง€๋ณด์ˆ˜์— ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ํ•„์š”ํ•œ ๊ตฌ์„ฑ์š”์†Œ์—๋งŒ ๊ณต์œ ํ•˜๋„๋ก ํ•˜๋ฉฐ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์˜ ๋ถˆํ•„์š”ํ•œ ๊ฒฐํ•ฉ๋„๋ฅผ ๋ฐฉ์ง€ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

 

๋™์  ๋ชจ๋“ˆ

Nest์˜ ๋™์  ๋ชจ๋“ˆ (Dynamic Module)์€ ๋Ÿฐํƒ€์ž„์— ๋ชจ๋“ˆ์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค๋‹ˆ๋‹ค. ์ด๋Š” ํŠน์ • ์˜ต์…˜์ด๋‚˜ ์„ค์ •์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ •์˜ ๊ฐ€๋Šฅํ•œ ๋ชจ๋“ˆ์„ ์ƒ์„ฑํ•ด์•ผ ํ•  ๋•Œ ํŠนํžˆ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ๋™์  ๋ชจ๋“ˆ์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ๊ฐ„๋‹จํ•œ ๊ฐœ์š”์ž…๋‹ˆ๋‹ค.

import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';

@Module({
  providers: [Connection],
  exports: [Connection],
})
export class DatabaseModule {
  static forRoot(entities = [], options?): DynamicModule {
    const providers = createDatabaseProviders(options, entities);
    return {
      module: DatabaseModule,
      providers: providers,
      exports: providers,
    };
  }
}
ํžŒํŠธ
forRoot() ๋ฉ”์„œ๋“œ๋Š” ๋™์  ๋ชจ๋“ˆ์„ ๋™๊ธฐ์ ์œผ๋กœ ๋˜๋Š” ๋น„๋™๊ธฐ (Promise ๊ธฐ๋ฐ˜)๋กœ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ด ๋ชจ๋“ˆ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ @Module() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ์— ์ •์˜๋œ Connection ํ”„๋กœ๋ฐ”์ด๋”๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ forRoot() ๋ฉ”์„œ๋“œ์— ์ „๋‹ฌ๋œ entities์™€ options ๊ฐ์ฒด์— ๋”ฐ๋ผ, ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ์™€ ๊ฐ™์€ ์ถ”๊ฐ€์ ์ธ ํ”„๋กœ๋ฐ”์ด๋” ์ง‘ํ•ฉ๋„ ํ•จ๊ป˜ ๋…ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๋™์  ๋ชจ๋“ˆ์ด ๋ฐ˜ํ™˜ํ•˜๋Š” ์†์„ฑ๋“ค์€ ๊ธฐ๋ณธ ๋ชจ๋“ˆ์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ฎ์–ด์“ฐ์ง€ ์•Š๊ณ  ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹ ๋•๋ถ„์—, ์ •์ ์œผ๋กœ ์„ ์–ธ๋œ Connection ํ”„๋กœ๋ฐ”์ด๋”์™€ ๋™์ ์œผ๋กœ ์ƒ์„ฑ๋œ ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ ํ”„๋กœ๋ฐ”์ด๋”๋“ค์„ ๋ชจ๋‘ ํ•ด๋‹น ๋ชจ๋“ˆ์—์„œ export ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์ „์—ญ ๋ฒ”์œ„์—์„œ ๋™์  ๋ชจ๋“ˆ์„ ๋“ฑ๋กํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋ฐ˜ํ™˜ ๊ฐ์ฒด์˜ global ์†์„ฑ์„ true๋กœ ์„ค์ •ํ•˜์„ธ์š”.

{
  global: true,
  module: DatabaseModule,
  providers: providers,
  exports: providers,
}
์ฃผ์˜
์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, ๋ชจ๋“  ๊ฒƒ์„ ์ „์—ญ์œผ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋ฐ”๋žŒ์งํ•œ ์„ค๊ณ„ ๋ฐฉ์‹์ด ์•„๋‹™๋‹ˆ๋‹ค.

 

DatabaseModule์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ import ๋ฐ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [DatabaseModule.forRoot([User])],
})
export class AppModule {}

 

๋™์  ๋ชจ๋“ˆ์„ ๋‹ค์‹œ re-export (์žฌ๋‚ด๋ณด๋‚ด๊ธฐ) ํ•˜๋ ค๋ฉด, exports ๋ฐฐ์—ด์—์„œ forRoot() ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ  ๋ชจ๋“ˆ ์ž์ฒด๋งŒ ๋‚˜์—ดํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';

@Module({
  imports: [DatabaseModule.forRoot([User])],
  exports: [DatabaseModule],
})
export class AppModule {}

 

์ด ์ฃผ์ œ๋Š” Dynamic Modules ์žฅ์—์„œ ๋” ์ž์„ธํžˆ ๋‹ค๋ฃจ๊ณ  ์žˆ์œผ๋ฉฐ, ์ž‘๋™ํ•˜๋Š” ์˜ˆ์ œ๋„ ํ•จ๊ป˜ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํžŒํŠธ
์ด ์žฅ์—์„œ๋Š” ConfigurableModuleBuilder๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋†’์€ ์ˆ˜์ค€์˜ ์‚ฌ์šฉ์ž ์ •์˜๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋™์  ๋ชจ๋“ˆ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Reference