Spellbook is an Elixir library providing dynamic hierarchical configurations loading for your application. It is based on the ideas implemented in the Javascript node-config module.
It lets you define a set of default parameters, and extend them for different deployment environments (development, staging, production, etc.) or custom needs (client id, hostname, etc.).
Configurations are stored in default or custom folders containing configuration files and can be overridden and extended by environment variables.
Custom configuration static and dynamic filenames and file formats can be added as needed.
Add Spellbook as a dependency to your mix.exs
file.
defp deps do
[{:spellbook, "~> 2.0.3"}]
end
The API reference can be found here.
config = Spellbook.load_config_folder()
Using Spellbook.load_config_folder/0
by default will use the following filename templates (in the listed order and if they exist) with the {SOMETHING}
template variables substituted:
<CWD>/config/default.{EXT}
<CWD>/config/default-{INSTANCE}.{EXT}
<CWD>/config/{ENV}.{EXT}
<CWD>/config/{ENV}-{INSTANCE}.{EXT}
<CWD>/config/{SHORT_HOSTNAME}.{EXT}
<CWD>/config/{SHORT_HOSTNAME}-{INSTANCE}.{EXT}
<CWD>/config/{SHORT_HOSTNAME}-{ENV}.{EXT}
<CWD>/config/{SHORT_HOSTNAME}-{ENV}-{INSTANCE}.{EXT}
<CWD>/config/{FULL_HOSTNAME}.{EXT}
<CWD>/config/{FULL_HOSTNAME}-{INSTANCE}.{EXT}
<CWD>/config/{FULL_HOSTNAME}-{ENV}.{EXT}
<CWD>/config/{FULL_HOSTNAME}-{ENV}-{INSTANCE}.{EXT}
<CWD>/config/local.{EXT}
<CWD>/config/local-{INSTANCE}.{EXT}
<CWD>/config/local-{ENV}.{EXT}
<CWD>/config/local-{ENV}-{INSTANCE}.{EXT}
<CWD>/config/custom-env-variables.{EXT}
Spellbook will use the default environment ({ENV}
= dev
) and the full hostname of the machine the code gets executed on ({FULL_HOSTNAME}
= my-machine.spellbook.domain
). As the other template variables are not defined, the filenames using them are ignored.
The resulting filenames searched/merged will be:
<CWD>/config/default.json
<CWD>/config/default.yaml
<CWD>/config/dev.json
<CWD>/config/dev.yaml
<CWD>/config/my-machine.spellbook.domain.json
<CWD>/config/my-machine.spellbook.domain.yaml
<CWD>/config/my-machine.spellbook.domain-dev.json
<CWD>/config/my-machine.spellbook.domain-dev.yaml
<CWD>/config/local.json
<CWD>/config/local.yaml
<CWD>/config/local-dev.json
<CWD>/config/local-dev.yaml
<CWD>/config/custom-env-variables.json
<CWD>/config/custom-env-variables.yaml
By default Spellbook supports JSON and YAML file formats.
config = Spellbook.default_config()
|> Spellbook.add_filename_format("clients/#{brand}.#{ext}")
|> Spellbook.load_config(
folder: "./test/support/brand",
config_filename: "brand-conf",
vars: [instance: "job-processor", brand: "elixir", env: "prod", short_hostname: "worker"]
)
Here we specify a specific folder were to look for the configuration files (with the folder
option), a custom configuration file name (with the config_filename
option). The vars
configuration field is used to define the variable values used in the filename templates.
The Spellbook.default_config/0
function (and the Spellbook.load_config/0
one as well) configures the Spellbook to search for the following file templates:
./test/support/brand/{CONFIG\_FILENAME}.{EXT}
./test/support/brand/{CONFIG\_FILENAME}-{INSTANCE}.{EXT}
./test/support/brand/{CONFIG\_FILENAME}-{ENV}.{EXT}
./test/support/brand/{CONFIG\_FILENAME}-{SHORT_HOSTNAME}-{ENV}-{INSTANCE}.{EXT}
./test/support/brand/{CONFIG\_FILENAME}-{FULL_HOSTNAME}-{ENV}-{INSTANCE}.{EXT}
./test/support/brand/clients/{BRAND}.{EXT}
./test/support/brand/custom-env-variables.{EXT}
In this case the searched/merged files will be:
./test/support/brand/brand-conf.json
./test/support/brand/brand-conf.yaml
./test/support/brand/brand-conf-job-processor.json
./test/support/brand/brand-conf-job-processor.yaml
./test/support/brand/brand-conf-prod.json
./test/support/brand/brand-conf-prod.yaml
./test/support/brand/brand-conf-worker-prod-job-processor.json
./test/support/brand/brand-conf-worker-prod-job-processor.yaml
./test/support/brand/brand-conf-worker1.spellbook.domain-prod-job-processor.json
./test/support/brand/brand-conf-worker1.spellbook.domain-prod-job-processor.yaml
./test/support/brand/clients/elixir.json
./test/support/brand/clients/elixir.yaml
./test/support/brand/custom-env-variables.json
./test/support/brand/custom-env-variables.yaml
A configuration is just a Map.
iex> config = Spellbook.load_config_folder()
%{ "some" => %{ "value" => %{ "from" => %{ "config" => "a value" }}}}
iex> is_map(config) == true
true
You can access the configuration values using the standard language features
iex> value = config["some"]["value"]["from"]["config"]
"a value"
or using the Spellbook.get
method that supports dot notation to access elements deep down the configuration structure:
iex> value = Spellbook.get(config, "some.value.from.config")
"a value"
Some situations rely heavily on environment variables to configure secrets and settings best left out of a codebase. Spellbook lets you use map the environment variable names into your configuration structure using a custom-env-variables.{EXT}
file:
{
"database": {
"username": "DB_USERNAME",
"password": "DB_PASSWORD"
}
}
If the DB_USERNAME
and DB_PASSWORD
environment variable exist, they would override the values for database.username
and database.password
in the configuration.
A special syntax allows environment variables typecast as well:
{
"database": {
"port": "DB_PORT.integer"
}
}
Will convert the "DB_PORT" environment variable into an integer. Supported typecasts are:
- "integer" (also "int", "i")
- "float" (also "f")
- "boolean" (also "bool", "b"): converts "false", "f", "0" to false, everything else to true.
Custom environment variables have precedence and override all configuration files, including local.json
.
Spellbook is provided under the MIT license