Skip to content

Documentation for registerAsync property extraProviders #3029

Closed
@Evanion

Description

@Evanion

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

I was having an issue where a module (BankIdModule) needed an instance of HttpModule with a custom Agent configured with specific certificates.
These needed to be configurable from the BankIdModule, so I needed to be able to pass the options from the BankIdModule to the HttpModule. solving the register property of my DynamicModule was easy enough, but I was having a hard time with the registerAsync method. I read docs, check out the advanced concepts course section on Dynamic modules, Asked CoPilot, and ChatGPT 4o.

Finally with the help of brendonmfo on discord, it was solved with the extraProviders property that you can set on the HttpModule.registerAsync call. I couldn't find any documentation on this property. and all the solutions involved creating intermediate providers that you registered before registering the BankIdModule etc.

Discord Thread: https://discord.com/channels/520622812742811698/1241198797065818273

Describe the solution you'd like

A section in the dynamic modules article that talks about this property, and how to use it.
https://docs.nestjs.com/fundamentals/dynamic-modules#extending-auto-generated-methods

Teachability, documentation, adoption, migration strategy

In order to pass options from your module, to any imported module in it, you can use the extraProviders property to pass your modules providers to the imported module.

import { Module } from '@nestjs/common';

import {
  ASYNC_OPTIONS_TYPE,
  ConfigurableModuleClass,
  OPTIONS_TYPE,
} from './config.module-definition';
import { ConfigService } from './config.service';
import { HttpModule } from '@nestjs/axios';

@Module({
  providers: [ConfigService],
  exports: [ConfigService],
})
export class ConfigModule extends ConfigurableModuleClass {
  static register(options: typeof OPTIONS_TYPE): DynamicModule {
    return {
      // your custom logic here
      ...super.register(options),
    };
  }

  static registerAsync(moduleOptions: typeof ASYNC_OPTIONS_TYPE): DynamicModule {
    const {imports, providers, exports} = super.registerAsync(moduleOptions);
    return {
      imports: [...(imports ?? []), HttpModule.registerAsync({
        useFactory: (options: typeof OPTIONS_TYPE) => {
          // your modules OPTIONS_TYPE is now available
          return {};
        },
        inject: [CONFIG_MODULE_OPTIONS],
        extraProviders: providers, // <-- Pass the returned `providers` property from the `super` call above
      })],
      providers,
      exports
    };
  }
}

What is the motivation / use case for changing the behavior?

This is an undocumented API that would help when you need to pass configurations to internal submodules.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions