Daniel Gruszczyk
Daniel Gruszczyk

Reputation: 5612

How to call useFactory from within forRootAsync of a dynamic module?

I am trying to create a DynamicModule that will return different providers based on config value from ConfigService, but I am struggling to see how I can fetch that config from within the forRootAsync of my module. Top level code looks somehow line below.

App module

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
      isGlobal: true,
    }),
    PrometheusModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        enableMetrics: config.get('telemetry.enableMetrics'),
        counters: [httpRequestCounter],
        histograms: [httpRequestDuration],
      }),
    })
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule implements NestModule {}

PrometheusModule:

export interface PrometheusMopduleOpts {
  enableMetrics: boolean;
  counters: client.CounterConfiguration<string>[];
  histograms: client.HistogramConfiguration<string>[];
}

export interface PrometheusModuleAsyncOpts
  extends Pick<ModuleMetadata, 'imports'> {
  useFactory: (
    ...args: any[]
  ) => Promise<PrometheusMopduleOpts> | PrometheusMopduleOpts;
  inject: any[];
}

const defaultOpts: PrometheusMopduleOpts = {
  enableMetrics: false,
  counters: [],
  histograms: [],
};

@Global()
@Module({})
export class PrometheusModule {
  static forRoot(opts: PrometheusMopduleOpts = defaultOpts): DynamicModule {
    return {
      module: PrometheusModule,
      imports: opts.enableMetrics
        ? []// process opts.histograms & opts.counters
        : [],
      providers: opts.enableMetrics
      ? []// process opts.histograms & opts.counters
      : [],
      exports: ['METRICS_HOLDER'],
    };
  }

  static async forRootAsync(
    asyncOpts: PrometheusModuleAsyncOpts
  ): Promise<DynamicModule> {
    const opts = await asyncOpts.useFactory(); // <=== this will obviously return undefined!
    return PrometheusModule.forRoot(opts);
  }
}

The issue is now that await asyncOpts.useFactory(); call within forRootAsync will throw as it doesn't have ConfigService passed into it. Is there a way to get that config in there? Or am I doing this the wrong way around?

Upvotes: 1

Views: 44

Answers (0)

Related Questions