Etrigan Config
A plugable config management library for your NodeJS applications.
Why
Config management is one of those things which sometimes you don't realise how important it is until you are using it. Some of the reasons to use a config library like Etrigan config is:
- Eager validation
- Validate the type and shape of your config on application startup, preventing hard to debug crashes at runtime
- Very useful for automatic rollback on failed deployment
- Config heirachy
- Want to have defaults -> config file -> environmental variables -> command line param heirachy, no problems
- Easily change config source
- Want to move some of your config into a config file included in deployment? This is safe and easy using a config management library
Usage
import { environmentConfigDriver, jsonFileConfigDriver, loadConfig } from '@etrigan/config'
const envValues = environmentConfigDriver.read({
testConfig: 'TEST_CONFIG',
})
const fileValues = jsonFileConfigDriver.read('./config.json')
interface MyConfig {
testItem?: string
testItem2: string
}
const config = loadConfig<MyConfig>({
values: { ...fileValues, ...envValues },
defaults: {
testItem2: 'some value',
},
validateConfig: {
testItem: 'optional-string',
testItem2: 'required-string',
},
})
Drivers
The above example loads config directly in code, drivers allow you to load config based on other config values. The two included drivers are quite basic, drivers can be more advanced, loading from APIs.
Example:
const config = loadConfig<MyConfig>({
values: getConfigRecords('json://./config.dev.json'),
defaults: {
testItem2: 'some value',
},
validateConfig: {
testItem: 'optional-string',
testItem2: 'required-string',
},
})
You can also register your own drivers, for example:
import {
environmentConfigDriver,
loadConfig,
getConfigRecords,
registerDriver,
} from '@etrigan/config'
import { parameterStoreConfigDriver } from '@etrigan/config-driver-ssm'
const bootstrapConfig = loadConfig({
values: await environmentConfigDriver.read({
configDriver: 'CONFIG_DRIVER',
}),
validateConfig: {
configDriver: 'required-string',
},
})
registerDriver(parameterStoreConfigDriver)
const config = loadConfig<Config>({
values: await getConfigRecords(bootstrapConfig.configDriver),
validateConfig: {
val: 'required-string',
secret: 'required-string',
},
})
The above ensure we have a value for configDriver from an environmental variable CONFIG_DRIVER
. It will then load the parameter store driver, getting all config values for the path /my-app/dev
and making them available as raw values.
This driver will automatically decode Secure-String values too if KMS is setup.
Config Validation
There are a few built in config validations. They are:
- required-boolean
- optional-boolean
- required-string
- optional-string
- non-empty-string
- optional-int
- required-int
Custom validations
If the above config validations are not enough, you can specify a function instead.
const config = loadConfig<Config>({
values,
validateConfig: {
val: value => {
if (value !== null && typeof value === 'object') {
return {
valid: true,
parsedValue: value,
}
}
if (typeof value === 'string') {
try {
return {
valid: true,
parsedValue: JSON.parse(value),
}
} catch {}
}
return {
valid: false,
}
},
},
})