Jonas Grønbek
Jonas Grønbek

Reputation: 2019

nestjs use ConfigService in simple provider class

is it possible to access nested configurations made by a configuration factory inside a simple provider class?

like:

/*Can't use ConfigService because there is no way of injecting it seemingly*/
export const databaseProviders = [
  {
    provide: 'SEQUELIZE',
    useFactory: async () => {
      const sequelize = new Sequelize({
        host: ConfigService.get<string>('pg.host'),
        port: ConfigService.get<number>('pg.port'),
        dialect: 'postgres',
        username: ConfigService.get<string>('pg.username'),
        password: ConfigService.get<string>('pg.password'),
        database: ConfigService.get<string>('pg.database')
      });
      sequelize.addModels([
         models...
      ]);
      await sequelize.sync(
        process.env.NODE_ENV === 'developent' && {
          force: true
        }
      );
      return sequelize;
    }
  }
];

config/configuration.ts

export default () => ({
  pg: {
    host: 'localhost',
    port: 5432,
    username: process.env.NODE_ENV logic...
    password: process.env.NODE_ENV logic...
    database: process.env.NODE_ENV logic...
  }
});

root.module.ts

...
import { ConfigModule } from '@nestjs/config';
import configuration from './config/configuration';

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

if not - is it possible to include ConfigService inside a simple provider class, that isn't annotated with @Injectable()

I would think not becuase https://docs.nestjs.com/techniques/configuration#getting-started

Using the ConfigService# To access configuration values from our ConfigService, we first need to >inject ConfigService. As with any provider, we need to import its >containing module - the ConfigModule - into the module that will use it (unless you set the isGlobal property in the options object passed to the ConfigModule.forRoot() method to true). Import it into a feature module as shown below.

However it is pretty clever that you can perform some logic based on process.env.NODE_ENV and dynamically change database configs between production, staging, development etc. So I would very much like a solution that would make this usable outside of just @Injectables

I assume one could make a simple util class in the root of the project that achieves the same thing, and use it inside of the application. But I think that solution has a lot of overhead.

Upvotes: 17

Views: 12551

Answers (1)

Jay McDoniel
Jay McDoniel

Reputation: 70111

You're so close to having the correct setup. As you're creating a factory provider, you can inject dependencies into the factory by using the inject key followed by an array of what to inject. In your case, it would look like this:

/*Can't use ConfigService because there is no way of injecting it seemingly*/
export const databaseProviders = [
  {
    provide: 'SEQUELIZE',
    inject: [ConfigService], //no worries for imports because you're using a global module
    useFactory: async (configService: ConfigService) => {
      const sequelize = new Sequelize({
        host: configService.get<string>('pg.host'),
        port: configService.get<number>('pg.port'),
        dialect: 'postgres',
        username: configService.get<string>('pg.username'),
        password: configService.get<string>('pg.password'),
        database: configService.get<string>('pg.database')
      });
      sequelize.addModels([
         models...
      ]);
      await sequelize.sync(
        process.env.NODE_ENV === 'developent' && {
          force: true
        }
      );
      return sequelize;
    }
  }
];

Upvotes: 32

Related Questions