[typescript-nestjs] allow configuration with forRootAsync (#15269) (#16112)

This commit is contained in:
Bernhard Wittmann 2023-07-22 20:38:52 +02:00 committed by GitHub
parent 3c5b119252
commit b7346d09eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 288 additions and 3 deletions

View File

@ -105,6 +105,31 @@ import { BASE_PATH } from '{{npmName}}';
export class AppModule {} export class AppModule {}
``` ```
### Configuring the module with `forRootAsync`
You can also use the Nestjs Config Module/Service to configure your app with `forRootAsync`.
```
@Module({
imports: [
ApiModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService): Configuration => {
const params: ConfigurationParameters = {
// set configuration parameters here.
basePath: config.get('API_URL'),
};
return new Configuration(params);
},
})
],
declarations: [ AppComponent ],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
```
#### Using @nestjs/cli #### Using @nestjs/cli
First extend your `src/environments/*.ts` files by adding the corresponding base path: First extend your `src/environments/*.ts` files by adding the corresponding base path:

View File

@ -5,7 +5,7 @@ import { HttpModule, HttpService } from '@nestjs/axios';
{{^useAxiosHttpModule}} {{^useAxiosHttpModule}}
import { DynamicModule, HttpService, HttpModule, Module, Global } from '@nestjs/common'; import { DynamicModule, HttpService, HttpModule, Module, Global } from '@nestjs/common';
{{/useAxiosHttpModule}} {{/useAxiosHttpModule}}
import { Configuration } from './configuration'; import { AsyncConfiguration, Configuration, ConfigurationFactory } from './configuration';
{{#apiInfo}} {{#apiInfo}}
{{#apis}} {{#apis}}
@ -33,5 +33,49 @@ export class ApiModule {
}; };
} }
/**
* Register the module asynchronously.
*/
static forRootAsync(options: AsyncConfiguration): DynamicModule {
const providers = [...this.createAsyncProviders(options)];
return {
module: ApiModule,
imports: options.imports || [],
providers,
exports: providers,
};
}
private static createAsyncProviders(options: AsyncConfiguration): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncConfigurationProvider(options)];
}
return [
this.createAsyncConfigurationProvider(options),
{
provide: options.useClass,
useClass: options.useClass,
},
];
}
private static createAsyncConfigurationProvider(
options: AsyncConfiguration,
): Provider {
if (options.useFactory) {
return {
provide: Configuration,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
return {
provide: Configuration,
useFactory: async (optionsFactory: ConfigurationFactory) =>
await optionsFactory.createConfiguration(),
inject: [options.useExisting || options.useClass],
};
}
constructor( httpService: HttpService) { } constructor( httpService: HttpService) { }
} }

View File

@ -1,3 +1,5 @@
import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
export interface ConfigurationParameters { export interface ConfigurationParameters {
apiKeys?: {[ key: string ]: string}; apiKeys?: {[ key: string ]: string};
username?: string; username?: string;
@ -77,3 +79,27 @@ export class Configuration {
return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
} }
} }
export interface ConfigurationFactory {
createConfiguration(): Promise<Configuration> | Configuration;
}
export interface AsyncConfiguration extends Pick<ModuleMetadata, 'imports'> {
/**
* The `useExisting` syntax allows you to create aliases for existing providers.
*/
useExisting?: Type<ConfigurationFactory>;
/**
* The `useClass` syntax allows you to dynamically determine a class
* that a token should resolve to.
*/
useClass?: Type<ConfigurationFactory>;
/**
* The `useFactory` syntax allows for creating providers dynamically.
*/
useFactory?: (...args: any[]) => Promise<Configuration> | Configuration;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
inject?: any[];
}

View File

@ -105,6 +105,31 @@ import { BASE_PATH } from '@openapitools/typescript-nestjs-petstore';
export class AppModule {} export class AppModule {}
``` ```
### Configuring the module with `forRootAsync`
You can also use the Nestjs Config Module/Service to configure your app with `forRootAsync`.
```
@Module({
imports: [
ApiModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService): Configuration => {
const params: ConfigurationParameters = {
// set configuration parameters here.
basePath: config.get('API_URL'),
};
return new Configuration(params);
},
})
],
declarations: [ AppComponent ],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
```
#### Using @nestjs/cli #### Using @nestjs/cli
First extend your `src/environments/*.ts` files by adding the corresponding base path: First extend your `src/environments/*.ts` files by adding the corresponding base path:

View File

@ -1,5 +1,5 @@
import { DynamicModule, HttpService, HttpModule, Module, Global } from '@nestjs/common'; import { DynamicModule, HttpService, HttpModule, Module, Global } from '@nestjs/common';
import { Configuration } from './configuration'; import { AsyncConfiguration, Configuration, ConfigurationFactory } from './configuration';
import { PetService } from './api/pet.service'; import { PetService } from './api/pet.service';
import { StoreService } from './api/store.service'; import { StoreService } from './api/store.service';
@ -27,5 +27,49 @@ export class ApiModule {
}; };
} }
/**
* Register the module asynchronously.
*/
static forRootAsync(options: AsyncConfiguration): DynamicModule {
const providers = [...this.createAsyncProviders(options)];
return {
module: ApiModule,
imports: options.imports || [],
providers,
exports: providers,
};
}
private static createAsyncProviders(options: AsyncConfiguration): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncConfigurationProvider(options)];
}
return [
this.createAsyncConfigurationProvider(options),
{
provide: options.useClass,
useClass: options.useClass,
},
];
}
private static createAsyncConfigurationProvider(
options: AsyncConfiguration,
): Provider {
if (options.useFactory) {
return {
provide: Configuration,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
return {
provide: Configuration,
useFactory: async (optionsFactory: ConfigurationFactory) =>
await optionsFactory.createConfiguration(),
inject: [options.useExisting || options.useClass],
};
}
constructor( httpService: HttpService) { } constructor( httpService: HttpService) { }
} }

View File

@ -1,3 +1,5 @@
import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
export interface ConfigurationParameters { export interface ConfigurationParameters {
apiKeys?: {[ key: string ]: string}; apiKeys?: {[ key: string ]: string};
username?: string; username?: string;
@ -77,3 +79,27 @@ export class Configuration {
return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
} }
} }
export interface ConfigurationFactory {
createConfiguration(): Promise<Configuration> | Configuration;
}
export interface AsyncConfiguration extends Pick<ModuleMetadata, 'imports'> {
/**
* The `useExisting` syntax allows you to create aliases for existing providers.
*/
useExisting?: Type<ConfigurationFactory>;
/**
* The `useClass` syntax allows you to dynamically determine a class
* that a token should resolve to.
*/
useClass?: Type<ConfigurationFactory>;
/**
* The `useFactory` syntax allows for creating providers dynamically.
*/
useFactory?: (...args: any[]) => Promise<Configuration> | Configuration;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
inject?: any[];
}

View File

@ -105,6 +105,31 @@ import { BASE_PATH } from '@openapitools/typescript-nestjs-petstore';
export class AppModule {} export class AppModule {}
``` ```
### Configuring the module with `forRootAsync`
You can also use the Nestjs Config Module/Service to configure your app with `forRootAsync`.
```
@Module({
imports: [
ApiModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService): Configuration => {
const params: ConfigurationParameters = {
// set configuration parameters here.
basePath: config.get('API_URL'),
};
return new Configuration(params);
},
})
],
declarations: [ AppComponent ],
providers: [],
bootstrap: [ AppComponent ]
})
export class AppModule {}
```
#### Using @nestjs/cli #### Using @nestjs/cli
First extend your `src/environments/*.ts` files by adding the corresponding base path: First extend your `src/environments/*.ts` files by adding the corresponding base path:

View File

@ -1,6 +1,6 @@
import { DynamicModule, Module, Global } from '@nestjs/common'; import { DynamicModule, Module, Global } from '@nestjs/common';
import { HttpModule, HttpService } from '@nestjs/axios'; import { HttpModule, HttpService } from '@nestjs/axios';
import { Configuration } from './configuration'; import { AsyncConfiguration, Configuration, ConfigurationFactory } from './configuration';
import { PetService } from './api/pet.service'; import { PetService } from './api/pet.service';
import { StoreService } from './api/store.service'; import { StoreService } from './api/store.service';
@ -28,5 +28,49 @@ export class ApiModule {
}; };
} }
/**
* Register the module asynchronously.
*/
static forRootAsync(options: AsyncConfiguration): DynamicModule {
const providers = [...this.createAsyncProviders(options)];
return {
module: ApiModule,
imports: options.imports || [],
providers,
exports: providers,
};
}
private static createAsyncProviders(options: AsyncConfiguration): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncConfigurationProvider(options)];
}
return [
this.createAsyncConfigurationProvider(options),
{
provide: options.useClass,
useClass: options.useClass,
},
];
}
private static createAsyncConfigurationProvider(
options: AsyncConfiguration,
): Provider {
if (options.useFactory) {
return {
provide: Configuration,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
return {
provide: Configuration,
useFactory: async (optionsFactory: ConfigurationFactory) =>
await optionsFactory.createConfiguration(),
inject: [options.useExisting || options.useClass],
};
}
constructor( httpService: HttpService) { } constructor( httpService: HttpService) { }
} }

View File

@ -1,3 +1,5 @@
import { ModuleMetadata, Type } from '@nestjs/common/interfaces';
export interface ConfigurationParameters { export interface ConfigurationParameters {
apiKeys?: {[ key: string ]: string}; apiKeys?: {[ key: string ]: string};
username?: string; username?: string;
@ -77,3 +79,27 @@ export class Configuration {
return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json'); return mime != null && (jsonMime.test(mime) || mime.toLowerCase() === 'application/json-patch+json');
} }
} }
export interface ConfigurationFactory {
createConfiguration(): Promise<Configuration> | Configuration;
}
export interface AsyncConfiguration extends Pick<ModuleMetadata, 'imports'> {
/**
* The `useExisting` syntax allows you to create aliases for existing providers.
*/
useExisting?: Type<ConfigurationFactory>;
/**
* The `useClass` syntax allows you to dynamically determine a class
* that a token should resolve to.
*/
useClass?: Type<ConfigurationFactory>;
/**
* The `useFactory` syntax allows for creating providers dynamically.
*/
useFactory?: (...args: any[]) => Promise<Configuration> | Configuration;
/**
* Optional list of providers to be injected into the context of the Factory function.
*/
inject?: any[];
}