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?