2

I have reviewed questions here, and they didn't help with my problem:

I want to create an async provider that will fetch configs from remote repository, which I implemented like this:


import { Injectable, Provider } from '@nestjs/common';
@Injectable()
export class ApiConfigService {
  private config: any;

  public async init() {
    await new Promise((resolve) => setTimeout(resolve, 500));

    this.config = {
      data: 3,
    };
  }
}

export const API_CONFIG_FACTORY = 'API_CONFIG_FACTORY';

const createApiConfigFactory = () => {
  return {
    generate: async function () {
      const apiConfigService = new ApiConfigService();
      await apiConfigService.init();
      return apiConfigService;
    },
  };
};

export const ApiConfigFactory: Provider = {
  provide: API_CONFIG_FACTORY,
  useFactory: createApiConfigFactory,
};

api-config.module.ts:

import { Module } from '@nestjs/common';
import { ApiConfigFactory } from './api-config.service';

@Module({
  imports: [],
  providers: [ApiConfigFactory],
  exports: [ApiConfigFactory],
})
export class ApiConfigModule {}

I also want to use that module in nestjs ThrottlerModule but when I try to do so:

import { Module } from '@nestjs/common';
import { ThrottlerModule } from '@nestjs/throttler';
import { ApiConfigModule } from './api-config/api-config.module';
import { ApiConfigFactory } from './api-config/api-config.service';

@Module({
  imports: [
    ApiConfigModule,
    ThrottlerModule.forRootAsync({
      imports: [ApiConfigModule],
      inject: [ApiConfigFactory],
      useFactory: (config: any) => {
        console.log('@config');
        console.log(config);

        return {
          ttl: config.get('throttle_api_ttl'),
          limit: config.get('throttle_api_limit'),
        };
      },
    }),
  ],
})
export class AppModule {}

It returns this error:

Error: Nest can't resolve dependencies of the THROTTLER:MODULE_OPTIONS (?). Please make sure that the argument [object Object] at index [0] is available in the ThrottlerModule context.

Potential solutions:
- If [object Object] is a provider, is it part of the current ThrottlerModule?
- If [object Object] is exported from a separate @Module, is that module imported within ThrottlerModule?
  @Module({
    imports: [ /* the Module containing [object Object] */ ]
  })

How can I successfully implement async config provider that I would be able to inject into ThrottlerModule?

Thanks in advance for your time!

Liam
  • 27,717
  • 28
  • 128
  • 190
Ruslan Plastun
  • 1,985
  • 3
  • 21
  • 48

1 Answers1

1

In order to make your exact code working, just replace ApiConfigFactory by API_CONFIG_FACTORY, and type your config service received :

ThrottlerModule.forRootAsync({
  imports: [ApiConfigModule],
  inject: [API_CONFIG_FACTORY],                // -> Provider token HERE
  useFactory: (config: ApiConfigService) => {  // -> ApiConfigService HERE
    return {
      ttl: config.get('throttle_api_ttl'),
      limit: config.get('throttle_api_limit'),
    };
  },
}),

But you can also simplify your code as below :

api-config.module.ts:

@Module({
  imports: [],
  providers: [
    {
      provide: ApiConfigService,
      useFactory: async () => {
        const apiConfigService = new ApiConfigService();
        await apiConfigService.init();
        return apiConfigService;
      },
    },
  ],
  exports: [ApiConfigService],
})
export class ApiConfigModule {}

and then in app.module.ts imports :

ThrottlerModule.forRootAsync({
  imports: [ApiConfigModule],
  inject: [ApiConfigService],
  useFactory: (config: ApiConfigService) => {
    return {
      ttl: config.get('throttle_api_ttl'),
      limit: config.get('throttle_api_limit'),
    };
  },
}),
Thierry Falvo
  • 5,892
  • 2
  • 21
  • 39
  • I'm stuck on a similar issue... How can I instantiate `ApiConfigService` (to then call its `init()` method) in case it does inject 2 dependencies in the constructor? – Alberto Dallaporta May 17 '23 at 09:45