-
Notifications
You must be signed in to change notification settings - Fork 2
English__Theory__Using Environmennt Variables as Data Source
It is common practice to not add certain configuration values to configuration files because configuration files are checked into source control. It is common practice to not add, for example, product keys or account passwords because then anyone with access to source control can obtain said information.
A very common practice is to use environment variables to inject configuration data that cannot be written to configuration files.
wj-config
fully supports the use of environment variables as configuration data source. This is done quite simply
and all that is needed is to follow a particular naming convention in order to properly position the values in the
hierarchical configuration object.
Let's write a quick example:
import wjConfig, { buildEnvironment } from 'wj-config';
import mainConfig from './config.json' assert { type: 'json' };
const myEnvs = [ 'Dev', 'PreProd', 'Prod' ];
const env = buildEnvironment(process.env.NODE_ENV, myEnvs);
const config = await wjConfig()
.includeEnvironment(env)
.addObject(mainConfig).name('Main')
.addPerEnvironment((b, e) => b.addObject(loadJsonFile(`./config.${e}.json`)))
.addEnvironment(process.env, 'APP_')
.build();
export default config;
This example builds on the conditional per-environment example discussed here
and adds the line .addEnvironment(process.env, 'APP_')
. The source is added last, so it means that values coming
from environment variables have the highest priority, and in the event of collision, the values defined in environment
variables will have precedence over any other values. The example is for a NodeJS application.
What you see in the example is all you need to add to bring environment variables into your final configuration object.
There are, however, 2 conditions that must be met by individual environment variables to qualify:
- The environment variable's name must start with the specified prefix, which was set to
APP_
in the example. - The environment variable's name must use double underscores (
__
) to separate the names of the various hierarchical levels, called nodes.
The final property value that is not a node is called leaf.
The first one is, hopefully, pretty straightforward: If you have an environment variable called MYVAR
, it won't
participate in the configuration building process because its name doesn't start with the specified APP_
prefix. If
its name is APP_MYVAR
, then it will participate in the configuration building process.
A prefix is always required, and if none is specified, then the default OPT_
is assumed.
The second condition probably requires a bit more explanation, so read the next section to fully understand it.
As you know by now, wj-config
produces a hierarchical configuration object. This means that the final
configuration object contains properties, and said properties may be objects with sub-properties, and so on until the
end of time.
This hierarchical nature is not available in system environment variables. The collection of environment variables is a flat collection of key/value pairs. Therefore, in order to allow an environment variable to specify its hierarchical position properly, its name may separate the node names using double underscores.
As example, let's describe a final configuration object:
{
"app": {
"title": "My App",
"version": "v1.0.0"
},
"db": {
"server": "mydbserver.example.com",
"port": 1433,
"username": "sys_app",
"password": "from-environment-please"
}
}
In our example, we have a section called db
that contains database connection information. The database connection
cannot be anonymous and therefore requires username and password, but the password cannot be saved into any JSON file
due to security concerns, and instead we want it injected via an environment variable. The question is: What must we
name this environment variable so the final configuration object has the password in the desired path? The desired
path, in case is not clear, is db.password
.
Simple: The environment variable's name must be <prefix>db__password
, where <prefix>
is whatever prefix was
specified during configuration construction. Using the example above, the name would then have to be
APP_db__password
.
There is no limit to the number of node names that the variable can have as long as the host system allows it.
IMPORTANT: JavaScript is a case-sensitive language, so the environment variable's name must match the JavaScript expected name, exactly. Using all-capital names probably won't work.
It is possible to not specify any hierarchy at all, in which case the value will be imported at the root level of
the final configuration object. As example, the environment variable APP_test=Hi!
will create the test
property
at the configuration root with the value 'Hi!'
(a string value).
The environment variables data source is a specialized dictionary data source. Dictionary data sources undergo data type coercion, and therefore environment variable values do too. Read the details here.
Contents
- English
- Theory
- JavaScript Concepts
- Data Sources
- Español
- Teoría