I believe that the way Nestjs is bootstraped could be improved by allowing the definition of the container before the definition of the application.
Take as an example a ConfigService
that would read all the variables in .env
in order to use them as options to define a new Nestjs Microservice while having the following code, how would you do it?
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
transport: Transport.RMQ,
options: {
urls: [
'amqp://guest:guest@localhost:5672',
],
queue: 'test',
queueOptions: { durable: true },
},
});
...
}
At the moment only 2 solutions come in mind:
ApplicationContext
to be able to get the ConfigService
from the container to use it for instantiating the microservice.DependencyInjection
I believe that this could be done by instantiating the ApplicationContext
that loads up the Container
and then use the ApplicationContext
as a parameter for the NestFactory.createMicroservice
method.
In order to support backwards compatibility you could even allow both the current way in case the paramenter a Module or the following one in case it is an instance of an ApplicationContext
async function bootstrap() {
const app = await NestFactory.createApplicationContext(AppModule);
const config = app.get(ConfigService);
const microservice = await NestFactory.createMicroservice(app, {
transport: Transport.RMQ,
options: {
urls: [
config.amqpUrl,
],
queue: config.queue,
queueOptions: { durable: true },
},
});
...
}
LoggerService
via DependecyInjection
and also allow setting config
options on it in order to call external services like Logstash
etc.@kamilmysliwiec is this a planned feature?
I found this solution ->
const app = await NestFactory.create(AppModule, {
logger: new Logger(),
})
const configService = app.get<ConfigService>(ConfigService)
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.RMQ,
options: {
urls: [amqp://${configService.get<string>('rabbitmq.host')}:${configService.get<number>
('rabbitmq.port')}],
queue: 'authentication',
queueOptions: {
durable: false,
},
},
})
app.startAllMicroservices(() => {
logger.log('Microservice is listening...')
})
this is work (usual MICROSERVICES) ! but this appear not work for websockets
I`m implementing Nest.js powered microservice and I need to do two things. Firstly, I need to get a configuration service in my main.ts file, and pass it as a constructor param to a custom transport strategy. Secondly, I need to do some bootstrapping actions in my service after microservice was bootstrapped.
The issue I faced seems related to this issue: when I`m using app = await NestFactory.create(AppModule)
and then app.connectMicroservice({strategy: myCustomStrategy})
- _onApplicationBootstrap_ event has not fired. But when I`m using appContext = await NestFactory.createApplicationContext(AppModule)
and then microservice = await NestFactory.createMicroservice(appContext, {strategy: myCustomStrategy})
- there is an error 'metatype is not a constructor' raised at _NestFactoryStatic.createMicroservice._
So for now I don`t understand, how I can pass correct environment config and catch the bootstrapping event simultaneously. Please, help me to figure out, if it can be done somehow.
I found this solution ->
const app = await NestFactory.create(AppModule, { logger: new Logger(), }) const configService = app.get<ConfigService>(ConfigService) app.connectMicroservice<MicroserviceOptions>({ transport: Transport.RMQ, options: { urls: [amqp://${configService.get<string>('rabbitmq.host')}:${configService.get<number> ('rabbitmq.port')}], queue: 'authentication', queueOptions: { durable: false, }, }, }) app.startAllMicroservices(() => { logger.log('Microservice is listening...') })
this is work (usual MICROSERVICES) ! but this appear not work for websockets
The one bit that becomes a sticking point with this example is that lifecycle methods do not work.
I found this solution ->
const app = await NestFactory.create(AppModule, { logger: new Logger(), }) const configService = app.get<ConfigService>(ConfigService) app.connectMicroservice<MicroserviceOptions>({ transport: Transport.RMQ, options: { urls: [amqp://${configService.get<string>('rabbitmq.host')}:${configService.get<number> ('rabbitmq.port')}], queue: 'authentication', queueOptions: { durable: false, }, }, }) app.startAllMicroservices(() => { logger.log('Microservice is listening...') })
this is work (usual MICROSERVICES) ! but this appear not work for websockets
The one bit that becomes a sticking point with this example is that lifecycle methods do not work.
Yes, but you can call the app.init method manually
app.startAllMicroservices(async () => {
// Calls the Nest lifecycle events.
await app.init()
logger.log('Microservice is listening...')
})
Is this gonna be solved or stay this way with the current workarounds, in my opinion this is pretty trivial usage
Most helpful comment
@kamilmysliwiec is this a planned feature?