Sources
A sequence of composable ConfigurationSource implementations provide field assignments to be processed by the
schema.
Each ConfigurationSource implements a load method that returns a map of field paths (hierarchical
dotted child schema names and field names) associated with value assignments.
For example, the field assignments output from a source might look like:
{
"debug": true,
"basics.verbose": true,
"basics.codes": [ "5xx", "z10", "123" ],
"server.host": "localhost",
"server.port": "8081",
"server.protocol": "https"
}
technically, it would be the Map equivalent.
Sources each have a defined priority sequence number. The highest numbered configuration source
in the sequence defining a field path assignment takes precedence. These are defined in
ConfigurationSource.DefaultSequence:
SYSTEM_DEFAULTS: 100 (priority used by schema defaults)
MODULES: 200 (used by ModuleManager for dependency injection)
SECRETS: 300 (for extension libraries to use)
APP_DEFAULTS: 400 (applications may reuse schemas and have their own defaults)
ENVIRONMENT: 500 (environment variables)
ARGUMENTS: 600 (command line)
SERVER: 700 (externally loaded configuration)
CONFIGURATION: 800 (config files)
OVERRIDES: 900 (forced settings from the application)
(Using an explicit sequence number allows the registration of a user-provided source to be easily sorted into the set of existing sources.)
Unlike some configuration libraries, Configurator defaults to prioritizing config files over
the command line and environment variables. This is to enable hot-reloading of configuration.
The environment and command line are immutable once the application starts, but a config file
can be updated dynamically!
It isn't magic.
If you don't pass in your own source list to Configurator, it simply creates a default list
that aligns with ConfigurationSource.DefaultSequence.
this.registerConfigurationSource(new DefaultsSource()); // system/schema defaults
this.registerConfigurationSource(new ObjectSource({
contextFieldName: 'defaults'
})); // app defaults
this.registerConfigurationSource(new EnvironmentSource());
this.registerConfigurationSource(new CommandLineSource());
this.registerConfigurationSource(new JsonFileSource({
contextFieldName: configContextFieldName
}));
this.registerConfigurationSource(new ObjectSource({
contextFieldName: 'overrides', sequence: ConfigurationSource.DefaultSequence.OVERRIDES
}));
ConfigurationSource
This section is only interesting if you are implementing your own source.
ConfigurationSource is an abstract base class that must be initialized via super:
constructor(name, options)
constructor(options)
| Param | Type | Description |
|---|---|---|
name | string | name of the source |
[options] | object | Optional settings (described below) |
[options.name] | string | Alternative way to specify the name |
[options.sequence] | number | Priority for this source (default: 1000) |
You must provide an implementation for load that returns a Map from a dotted field path
to the configured value (that will later be resolved by a type resolver).
It is acceptable to peek at the field type in order to interpret inputs; (most commonly to
identify array-like fields).
async load(schema:ConfigurationSchema, context:object, options:object):Map<string,any>
| Param | Type | Description |
|---|---|---|
schema | ConfigurationSchema | schema to use for field paths |
context | object | the context object passed to Configurator.configure |
[options] | string | load options (only one at the moment) |
[options.strict] | boolean | whether to throw an error for unknown settings |
Returns: Map<string,any>
Example:
class MyConfigurationSource extends ConfigurationSource {
constructor(name, options) {
super(name, options);
}
async load(schema, context, options) {
const fieldPaths = schema.getAllFieldPaths();
const fieldAssignments = new Map();
// source logic here
return fieldAssignments;
}
}