@itanium.be/nestjs-dynamic-config
v0.0.11
Published
Hot-reloading drop-in replacement configuration provider for NestJS
Downloads
4
Maintainers
Readme
nestjs-dynamic-config
Drop-in dynamic configuration module for Nest with automatic reload on file update and environment variable substitution
Install
npm install -s @itanium.be/nestjs-dynamic-config
Usage
create a new Nestjs app
Create a .js
or .json
configuration file
// <project root>/config.js
exports.default = () => ({
name: "some-name",
length: 100,
database: {
host: "myHost",
user: "root",
},
environment: '{{ENV_NODE_ENV}}',
app_name: '{{pkg.name}}',
});
Remark: In this case the configuration file is located in the project's root. In real life you'll probably want your config file to be located in a specific folder so that - when you're deploying in docker containers - you can link to the host filesystem
Define the module in your project's app module
@Module({
imports: [
ConfigModule.register({
configFile: "config.js",
}),
],
controllers: [
/* your controllers */
],
providers: [
/* your providers */
],
})
export class AppModule {}
The configuration file location is resolved relative to the project root. You can add path information to the configFile
option.
There's plenty more options that can be passed in the register
function, most of them work the same like in the original @nestjs/config module.
Use the configuration module in your code
Change the app.controller.ts
code to
@Controller()
export class AppController {
private readonly nameProxy: () => string;
constructor(private readonly config: ConfigService) {
this.nameProxy = config.createProxy("name");
}
@Get("name")
getName() {
return this.nameProxy();
}
@Get("db")
getDb() {
return this.config.get("database");
}
@Get("all")
getAll() {
return this.config.config;
}
}
Run your app and call the API endpoints using your favorite browser. Change the name
property in the config file and reload the browser.
This code demonstrates
- dynamic configuration updating
- different ways to consume the configuration
- environment variable substitution
Proxies
The this.nameProxy
is a proxy to the "name" configuration element. When the name
configuration element in the config file changes, the change is immediately reflected without the need to restart the nest app.
A proxy is created with config.createProxy(configElementName)
. A second default
argument can be passed to createProxy
. When the configuration element is not found and a default value was defined then the default value will be returned from the proxy.
A generic parameter can be passed to the createProxy
function . f.i. config.createProxy<number>(['wellKnown'.'numbers'.'pi'])
. If the generic parameter is omitted, string
is assumed.
.get<T>(name, default) function
The configService.get(configElementName)
can also be used to extract configuration elements. Beware that the information will not be automatically refreshed in this case. Next to the feature of the original, the .get()
can also be called with an array of strings that make a path into the configuration object. These statements are equivalent
config.get<object>('database')['port'];
config.get<{ port: number }>('database').port;
config.get<number>('database.host');
config.get(['database', 3306]); // generic type inferred from `default` value
Variable substitution
Configuration elements defined as {{ENV_xxx}}
or {{pkg.xxx}}
will be substituted either from environment variables or from the package.json
file.
For instance, {{ENV_NODE_ENV}}
will be substituted with the value of process.env.NODE_ENV
, {{pkg.version}}
will be substituted with the package version.
.env
file are loaded with the help of the dotenv package. All the usual naming rules apply for the filenames. Multiple files can be loaded.
Debugging
This module will try it's best to collect all the needed information. It will make a educated guess about where the root folder of your project is located and what .env
files exist. This process can fail depending on your project setup. If you experience problems, activate debugging by adding the below options in the .register()
function
{
...
debug: true,
logger: new ConsoleLogger(),
}
Hint:
Consolelogger
is imported from'@nestjs/common'
Validation
A Joi validation object can be passed to sanitize the configuration. These properties are available
validationSchema
Joi objectvalidationOptions
validation optionsvalidationCallback
function to be called in case of validation errors
Add this code to your app.module.ts
const validationSchema = Joi.object({
other: Joi.string().default('my other string'),
});
@Module({
imports: [
ConfigModule.register({
...
validationSchema,
validationOptions: { allowUnknown: true },
validationCallback: (error: Joi.ValidationError) => console.log(error),
})],
...
})
Hint:
Joi
is imported from the'Joi'
module
Restart the Nestjs app and reload the browser. "other": "my other string"
will be in the displayed configuration even though it 's not in the configuration file.
That's because it is defined in the validation schema with a default value.
If you comment out the line with validationOptions
, an error message will be printed because the configuration file contains (many) elements that are not defined in the validationSchema.
If you also comment out the line where the validationCallback
is defined, the program will deliberately crash because it's configuration is not valid.
Crashing your program
This module will purposefully crash your program if the configuration file is not found, when it is not a *.js
or *.json
file or when validation fails. This is considered the best option because having your program run with missing or invalid configuration will usually be even worse.
To prevent this, you can
- set
validationCallback
when you use validation - the validation errors will be sent to the callback instead of printed to the screen (and crashing the program) - set
onLoadErrorCallback
- this callback will be called with the error thrown when attempting to load the configuration file and the program will not crash.