Dynamically Configuring Microservice Bootstrap
During setting up microservice in nestjs, I faced a challenge. By convention, and as illustrated in nestjs documentation, microservice is boostrapped using following convention.
import { NestFactory } from '@nestjs/core';
import { Transport, MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
url: 'xxx.url.com',
protoPackage: 'some/hard/coded/path',
}
},
);
await app.listen();
}
bootstrap();The above configuration, however, is static. Therefore, it includes hard coding, such as the port/url, transport method, etc.
I wanted to make the microservice configuration using .env variables, using ConfigService offered by @nestjs/config.
Therefore, I had to find a way to somehow import config module within the provided code, but it was difficult. From my research, I found an nestjs open discussion that illustrates the problem (link (opens in a new tab)).
I then decided to define an ApplicationConetext, and use configService that gets the ConfigService provider in my AppModule.
From the configSerivce, I defined my microserviceOptions. With these, I then created the actual app, and closed the temporary appContext.
Note that inorder to achieve this, my AppModule must import ConfigModule.
async function bootstrap() {
const appContext = await NestFactory.createApplicationContext(AppModule);
const configService = appContext.get(ConfigService);
const url = configService.get<string>('MICROSERVICE_APP_URL');
const microserviceOptions: MicroserviceOptions = {
transport: Transport.GRPC,
options: {
url,
protoPath: join(__dirname, '../app.proto'),
package: APP_PACKAGE_NAME,
},
};
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AuthModule,
microserviceOptions,
);
appContext.close();
await app.listen();
}
bootstrap();