Custom providers

Custom providers

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

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

์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์˜ต์…˜์„ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Use value

useValue ๊ตฌ๋ฌธ์€ ์ƒ์ˆ˜ ๊ฐ’์„ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ Nest ์ปจํ…Œ์ด๋„ˆ์— ๋„ฃ๊ฑฐ๋‚˜ ์‹ค์ œ ๊ตฌํ˜„์„ ๋ชจ์˜ ๊ฐ์ฒด๋กœ ๋Œ€์ฒด ํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

import { connection } from './connection';

const connectionProvider = {
  provide: 'CONNECTION',
  useValue: connection,
};

@Module({
  providers: [connectionProvider],
})
export class ApplicationModule {}

์ปค์Šคํ…€ ํ”„๋กœ ๋ฐ”์ด๋”๋ฅผ ์ฃผ์ž…ํ•˜๊ธฐ ์œ„ํ•ด @Inject()๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” ํ† ํฐ์ด๋ผ๋Š” ๋‹จ์ผ ์ธ์ˆ˜๋ฅผ ์ทจํ•ฉ๋‹ˆ๋‹ค.

@@filename()
@Injectable()
export class CatsRepository {
  constructor(@Inject('CONNECTION') connection: Connection) {}
}
@@switch
@Injectable()
@Dependencies('CONNECTION')
export class CatsRepository {
  constructor(connection) {}
}

info ํžŒํŠธ @Inject() ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋Š” @nestjs/common ํŒจํ‚ค์ง€์—์„œ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

import { CatsService } from './cats.service';

const mockCatsService = {};
const catsServiceProvider = {
  provide: CatsService,
  useValue: mockCatsService,
};

@Module({
  imports: [CatsModule],
  providers: [catsServiceProvider],
})
export class ApplicationModule {}

์œ„์˜ ์˜ˆ์—์„œ CatsService๋Š” ์ „๋‹ฌ ๋œ mockCatsService ๋ชจ์˜ ๊ฐ์ฒด๋กœ ์žฌ์ •์˜๋ฉ๋‹ˆ๋‹ค. ์ฆ‰, CatsService์ธ์Šคํ„ด์Šค๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ๋Œ€์‹  Nest๊ฐ€์ด ๊ณต๊ธ‰์ž๋ฅผ ์ด๋ฏธ ํ•ด๊ฒฐ๋œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผํ•˜๊ณ mockCatsService๋ฅผ ๋Œ€ํ‘œ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Use class

useClass ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์„ ํƒํ•œ ์š”์†Œ๋งˆ๋‹ค ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ถ”์ƒ (๋˜๋Š” ๊ธฐ๋ณธ) ConfigService ํด๋ž˜์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ˜„์žฌ ํ™˜๊ฒฝ์— ๋”ฐ๋ผ Nest๋Š” ๋‹ค๋ฅธ ๊ตฌ์„ฑ ์„œ๋น„์Šค ๊ตฌํ˜„์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

const configServiceProvider = {
  provide: ConfigService,
  useClass:
    process.env.NODE_ENV === 'development'
      ? DevelopmentConfigService
      : ProductionConfigService,
};

@Module({
  providers: [configServiceProvider],
})
export class ApplicationModule {}

warning ์•Œ๋ฆผ ์ปค์Šคํ…€ ํ† ํฐ ๋Œ€์‹  ConfigService ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋ฏ€๋กœ ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์žฌ์ •์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ฒฝ์šฐ ํด๋ž˜์Šค๊ฐ€ ConfigService์— ์ข…์†๋˜์–ด ์žˆ๋”๋ผ๋„ Nest๋Š” ์ œ๊ณต๋œ ํด๋ž˜์Šค (DevelopmentConfigService ๋˜๋Š” ProductionConfigService)์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋Œ€์‹  ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค.

Use factory

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

@@filename()
const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
})
export class ApplicationModule {}
@@switch
const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
})
export class ApplicationModule {}

info ํžŒํŠธ ํŒฉํ† ๋ฆฌ์— ๋‹ค๋ฅธ ์ œ๊ณต์ž๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ, inject ๋ฐฐ์—ด ์•ˆ์— ํ† ํฐ์„ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Nest๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ๋™์ผํ•œ ์ˆœ์„œ๋กœ ํ•จ์ˆ˜์˜ ์ธ์ˆ˜๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.

Use existing

useExisting์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์กด ๊ณต๊ธ‰์ž์˜ ๋ณ„์นญ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, AliasedLoggerService ํ† ํฐ์€ LoggerService์˜ ๋ณ„๋ช…์ž…๋‹ˆ๋‹ค.

@Injectable()
class LoggerService {}

const loggerAliasProvider = {
  provide: 'AliasedLoggerService',
  useExisting: LoggerService
};

@Module({
  providers: [LoggerService, loggerAliasProvider],
})
export class ApplicationModule {}

info ํžŒํŠธ LoggerService ์ธ์Šคํ„ด์Šค๋Š” AliasedLoggerService ํ† ํฐ์— ์˜ํ•ด ์ •์˜๋œ ์ธ์Šคํ„ด์Šค์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

Export custom provider

์‚ฌ์šฉ์ž ์ง€์ • ๊ณต๊ธ‰์ž๋ฅผ ๋‚ด๋ณด๋‚ด๋ ค๋ฉด ํ† ํฐ ๋˜๋Š” ์ „์ฒด ๊ฐœ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์ œ๋Š” ํ† ํฐ ์ผ€์ด์Šค๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

@@filename()
const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
  exports: ['CONNECTION'],
})
export class ApplicationModule {}
@@switch
const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
  exports: ['CONNECTION'],
})
export class ApplicationModule {}

๊ทธ๋Ÿฌ๋‚˜ ์ „์ฒด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

@@filename()
const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider: OptionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
  exports: [connectionFactory],
})
export class ApplicationModule {}
@@switch
const connectionFactory = {
  provide: 'CONNECTION',
  useFactory: (optionsProvider) => {
    const options = optionsProvider.get();
    return new DatabaseConnection(options);
  },
  inject: [OptionsProvider],
};

@Module({
  providers: [connectionFactory],
  exports: [connectionFactory],
})
export class ApplicationModule {}

Last updated

Was this helpful?