nestjsx / nestjs-config

Config module for nestjs using dotenv :key:
MIT License
698 stars 44 forks source link

[BUG] NestFactory.createApplicationContext - error Cannot read properties of undefined (reading 'getOrThrow') in module service #652

Open LBeckX opened 3 months ago

LBeckX commented 3 months ago

Issue type:

nestjs-config version "@nestjs/config": "3.2.3"

@nestjs/common+core or other package versions

Excepted behavior

I'm trying to build a console helper with NestJS that works with a Mongoose database. To build the Mongoose URI, I have created my own module which creates the URI for me. When I start the application normally, everything works as it should and the DatabaseService is injected and in this service I can access the ConfigService inside of my database.service.ts.

main.ts call: const app = await NestFactory.create(AppModule);

Actual behavior or outcome (for issue)

But, when I call the CLI tool and start the app with const app = await NestFactory.createApplicationContext(AppModule); I get the following error:

[Nest] 18400  - 22.08.2024, 16:53:40   ERROR [ExceptionHandler] Cannot read properties of undefined (reading 'getOrThrow')
TypeError: Cannot read properties of undefined (reading 'getOrThrow')
    at DatabaseService.getDatabaseUrl ([PATH]\src\module\database\database.service.ts:14:37)
    at InstanceWrapper.useFactory ([PATH]\src\app.module.ts:19:30)
    at Injector.instantiateClass ([PATH]\node_modules\@nestjs\core\injector\injector.js:368:55)
    at callback ([PATH]\node_modules\@nestjs\core\injector\injector.js:65:45)
    at async Injector.resolveConstructorParams ([PATH]\node_modules\@nestjs\core\injector\injector.js:144:24)
    at async Injector.loadInstance ([PATH]\node_modules\@nestjs\core\injector\injector.js:70:13)
    at async Injector.loadProvider ([PATH]\node_modules\@nestjs\core\injector\injector.js:97:9)
    at async [PATH]\node_modules\@nestjs\core\injector\instance-loader.js:56:13
    at async Promise.all (index 3)
    at async InstanceLoader.createInstancesOfProviders ([PATH]\node_modules\@nestjs\core\injector\instance-loader.js:55:9)

Replication/Example

my-console-tool.ts

async function bootstrap() {
  const app = await NestFactory.createApplicationContext(AppModule);

 ... my code ...

  app.close();
}

bootstrap();

app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { DatabaseModule } from './module/database/database.module';
import { DatabaseService } from './module/database/database.service';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),

    DatabaseModule,

    MongooseModule.forRootAsync({
      imports: [DatabaseModule],
      inject: [DatabaseService],
      useFactory: (databaseService: DatabaseService) => ({
        uri: databaseService.getDatabaseUrl(),
      }),
    }),
  ],
  controllers: [],
})
export class AppModule {
}

database.module.ts

import { Module } from '@nestjs/common';
import { DatabaseService } from './database.service';
import { ConfigModule } from '@nestjs/config';

@Module({
  imports: [
    ConfigModule,
  ],
  providers: [
    DatabaseService,
  ],
  exports: [
    DatabaseService,
  ],
})
export class DatabaseModule {
}

database.service.ts

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class DatabaseService {
  private readonly _logger = new Logger(DatabaseService.name);

  constructor(
    private configService: ConfigService,
  ) {
  }

  getDatabaseUrl(): string {
    const user = this.configService.getOrThrow('MONGO_USER');
    const password = this.configService.getOrThrow('MONGO_PASSWORD');
    const host = this.configService.getOrThrow('MONGO_HOST');
    const port = this.configService.getOrThrow('MONGO_PORT');
    const database = this.configService.getOrThrow('MONGO_DATABASE');
    return `mongodb://${user}:${password}@${host}:${port}/${database}`;
  }
}