Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Reimplementation] Improving the inject-ability with config providers #54

Open
bashleigh opened this issue Jan 24, 2019 · 1 comment
Open
Assignees
Labels
discussion enhancement New feature or request

Comments

@bashleigh
Copy link
Collaborator

bashleigh commented Jan 24, 2019

The idea

I've been debating for a while if the method of storing application configurations in an injectable class is the best approach. Since the AsyncProvider was added to nestjs it would be possible to await the loading of the config module to create providers for each file found from the glob.

The reason

This method would make the config providers easier to import into the constructors of injectables and would clear up implementation issues and the need for injecting the entire configuration class #30, #12.

Possible drawback

However it does mean that some functionality could be lost. Specifically the ConfigService would be rendered redundant unless we're able to inject all config providers as one provider into the ConfigService class.

If you like the idea give this comment a ❤️. If you don't, add a 👎.

TLDR;

Remove ConfigService injection and instead create a provider for each config file

ConfigModule async provider build

class ConfigModule {
  public static async asyncLoad(glob: string, options: ConfigOptions): Promise<DynamicModule> {
    const configs = await ConfigService.findByGlob(glob);
    configs.map(config => ({
      provide: configToken(config.fileName),
      useValue: config.value,
    }));
 
    return {
      module: ConfigModule,
      providers: configs,
      exports: configs,
    };
  }
}
@Controller()
export class ExampleController {
  constructor(@InjectConfig('filename') config) {}
}
@Injectable()
export class ExampleProvider {
  constructor(@InjectConfig('database') database, @InjectConfig('another') Another) {}
}
@Module({
  imports: [
    TypeOrmModule.forRootAsync((
      useFactory: (config) => config,
      inject: [configToken('database')],
    }),
  ],
})

Further possibilities

Types

Using types in the config could be very beneficial for validation and obviously typing in the project.

configs/app.config.ts

export default class AppConfig {
  port: number = process.env.PORT;
  development: boolean = process.env.NODE_ENV === 'development';
}
@Module({
  imports: [
    SomeModule.forRootAsync({
        useFactory: (config: AppConfig) => config,
        injects: [AppConfig],
    }),
  ],
})

or

@Injectable()
export class SomeClass {
  constructor(private readonly myConfig: AppConfig) {}
}

Without types

export default {
  '__provide': 'SOME_TOKEN',
  '__name': 'name_of_config',
  port: process.env.PORT,
}

This could then be injected with

@Module({
  providers: [
    {
        provide: SomeProvider,
        useFactory: (config) => config,
        inject: ['SOME_TOKEN'],
    },
  ],
})
@Injectable()
export class SomeClass {
  constructor(@Inject('SOME_TOKEN') private readonly config) {}
}

Or selected with ConfigService.get('name_of_config.port').

@bashleigh bashleigh added enhancement New feature or request discussion labels Jan 24, 2019
@bashleigh bashleigh self-assigned this Jan 24, 2019
@bashleigh bashleigh pinned this issue Jan 24, 2019
@bashleigh bashleigh removed their assignment Jan 28, 2019
@bashleigh
Copy link
Collaborator Author

If anyone is interested, I started an experimental repo for these v2 features/implementation changes https://github.com/bashleigh/nestjs-config-v2-prototype

@bashleigh bashleigh self-assigned this Mar 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant