I'am creating a microservice in NestJS. Now I want to use RabbitMQ to send messages to another service.
My question is: is it possible to import the RabbitmqModule based on a .env
variable? Such as:
USE_BROKER=false
. If this variable is false, than don't import the module?
RabbitMQ is imported in the GraphQLModule below.
@Module({
imports: [
GraphQLFederationModule.forRoot({
autoSchemaFile: true,
context: ({ req }) => ({ req }),
}),
DatabaseModule,
AuthModule,
RabbitmqModule,
],
providers: [UserResolver, FamilyResolver, AuthResolver],
})
export class GraphQLModule {}
RabbitmqModule:
import { Global, Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
import { UserProducer } from './producers/user.producer';
@Global()
@Module({
imports: [
RabbitMQModule.forRootAsync(RabbitMQModule, {
useFactory: async (config: ConfigService) => ({
exchanges: [
{
name: config.get('rabbitMQ.exchange'),
type: config.get('rabbitMQ.exchangeType'),
},
],
uri: config.get('rabbitMQ.url'),
connectionInitOptions: { wait: false },
}),
inject: [ConfigService],
}),
],
providers: [UserProducer],
exports: [UserProducer],
})
export class RabbitmqModule {}
In other words, dynamic modules provide an API for importing one module into another, and customizing the properties and behavior of that module when it is imported, as opposed to using the static bindings we've seen so far.
The forRoot sets up the loading of the . env file and the forChild uses it in another module. The problem is that forChild is called before forRoot . The ConfigService would be injected with missing config because forRoot hasn't executed first.
Dependency injection is an inversion of control (IoC) technique wherein you delegate instantiation of dependencies to the IoC container (in our case, the NestJS runtime system), instead of doing it in your own code imperatively.
I think the recommended way to do so is to use the DynamicModule feature from NestJS.
It is explained here: https://docs.nestjs.com/fundamentals/dynamic-modules
Simply check your environment variable in the register function and return your Module object. Something like:
@Module({})
export class GraphQLModule {
static register(): DynamicModule {
const imports = [
GraphQLFederationModule.forRoot({
autoSchemaFile: true,
context: ({ req }) => ({ req }),
}),
DatabaseModule,
AuthModule]
if (process.env.USE_BROKER) {
modules.push(RabbitmqModule)
}
return {
imports,
providers: [UserResolver, FamilyResolver, AuthResolver],
};
}
}
Well I tried a simple workaround, in a small nest project, and it worked just fine. Check it out:
const mymodules = [TypeOrmModule.forRoot(typeOrmConfig), UsersModule];
if (config.get('importModule')) {
mymodules.push(PoopModule);
}
@Module({
imports: mymodules,
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
I created an "importModule" in my env/config, and tested it with true and false. If true my Poop module gets deployed, else it doesn't deploy, only the other modules.
Can you try the same in your project?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With