Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to access providers from DI while constructing a dynamic module #9046

Closed
1 task done
ajwootto opened this issue Jan 27, 2022 · 1 comment
Closed
1 task done
Labels
needs triage This issue has not been looked into type: enhancement 🐺

Comments

@ajwootto
Copy link

ajwootto commented Jan 27, 2022

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

There are times where I want to be able to construct a module dynamically, and make decisions within the "register" method using information that's only available in a DI context. A good example of this is:
"I want to change the set of controllers provided by a module using some configuration from the ConfigService"

Code Example:

@Module({})
export class MyModule {
  static register(): DynamicModule {
    const controllers = [VersionOneController]
    // What if I wanted to use the ConfigService here?
    if (process.env.ENABLE_V2_API) {
      controllers.push(VersionTwoController)
    }
    return {
      controllers
    };
  }
}

In the above, I'm able to use things like "process.env" to make a decision on which controllers to use, but I don't have a way to inject "ConfigService" to make that decision.

Describe the solution you'd like

If it's technically achievable and doesn't violate some principle of DI that I don't know about, I think it would be useful to be able to define a dynamic module that can be injected with providers in the "register"-style methods in order to make decisions about how that module should be constructed.

Teachability, documentation, adoption, migration strategy

Just a rough idea of how this could look (sort of borrowing the asynchronous providers syntax):

@Module({})
class MyModule {
    registerWithInjection(): DynamicModuleWithInjection {
        return {
            useFactory: (configService: ConfigService): DynamicModule => {
                const controllers = [VersionOneController]
                if (configService.get('ENABLE_V2')) {
                    controllers.push(VersionTwoController)
                }
                return {
                    module: MyModule,
                    controllers
                }
            },
            inject: [ConfigService]
        }
    }
}

Then you just use it like a regular dynamic module:

@Module({
  imports: [MyModule.registerWithInjection()]
})
class SomeOtherModule {}

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

The main reason I would love to be able to do this is so that I can use our feature flagging system to adjust the behaviour of modules, and enable or disable code paths. If I could inject my "featureFlagService" into a dynamic module "register" method, I'd be able to make decisions on how the module should be constructed without having to go outside the DI context and directly import an instance of the feature flagging client.

In the controller example, being able to control which ones are included at the module level gives me a really simple way to disable a certain set of APIs, while also having that decision reflected in the generated Swagger docs.

This has also come up before in some other questions, but was left inconclusive in those cases:
#601
https://stackoverflow.com/questions/65355892/can-you-import-a-nestjs-module-on-condition
https://stackoverflow.com/questions/64234793/dynamic-module-dependency-injection

@ajwootto ajwootto added needs triage This issue has not been looked into type: enhancement 🐺 labels Jan 27, 2022
@kamilmysliwiec
Copy link
Member

Creating dynamic/configurable modules should be much simpler in v9 with the addition of ConfigurableModuleBuilder class, see PR #9534. More details soon.

@nestjs nestjs locked and limited conversation to collaborators May 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs triage This issue has not been looked into type: enhancement 🐺
Projects
None yet
Development

No branches or pull requests

2 participants