Crate hydroconf[−][src]
Expand description
Quickstart
Suppose you have the following file structure:
├── config
│ ├── .secrets.toml
│ └── settings.toml
└── your-executable
settings.toml
:
[default]
pg.port = 5432
pg.host = 'localhost'
[production]
pg.host = 'db-0'
.secrets.toml
:
[default]
pg.password = 'a password'
[production]
pg.password = 'a strong password'
Then, in your executable source (make sure to add serde = { version = "1.0", features = ["derive"] }
to your dependencies):
use serde::Deserialize; use hydroconf::Hydroconf; #[derive(Debug, Deserialize)] struct Config { pg: PostgresConfig, } #[derive(Debug, Deserialize)] struct PostgresConfig { host: String, port: u16, password: String, } fn main() { let conf: Config = match Hydroconf::default().hydrate() { Ok(c) => c, Err(e) => { println!("could not read configuration: {:#?}", e); std::process::exit(1); } }; println!("{:#?}", conf); }
If you compile and execute the program (making sure the executable is in the
same directory where the config
directory is), you will see the following:
$ ./your-executable
Config {
pg: PostgresConfig {
host: "localhost",
port: 5432,
password: "a password"
}
}
Hydroconf will select the settings in the [default]
table by default. If you
set ENV_FOR_HYDRO
to production
, Hydroconf will overwrite them with the
production ones:
$ ENV_FOR_HYDRO=production ./your-executable
Config {
pg: PostgresConfig {
host: "db-0",
port: 5432,
password: "a strong password"
}
}
Settings can always be overridden with environment variables:
$ HYDRO_PG__PASSWORD="an even stronger password" ./your-executable
Config {
pg: PostgresConfig {
host: "localhost",
port: 5432,
password: "an even stronger password"
}
}
Environment variables
There are two formats for the environment variables:
- those that control how Hydroconf works have the form
*_FOR_HYDRO
; - those that override values in your configuration have the form
HYDRO_*
.
For example, to specify where Hydroconf should look for the configuration
files, you can set the variable ROOT_PATH_FOR_HYDRO
. In that case, it’s no
longer necessary to place the binary in the same directory as the
configuration. Hydroconf will search directly from the root path you specify.
Here is a list of all the currently supported environment variables to configure how Hydroconf works:
ROOT_PATH_FOR_HYDRO
: specifies the location from which Hydroconf should start searching configuration files. By default, Hydroconf will start from the directory that contains your executable;SETTINGS_FILE_FOR_HYDRO
: exact location of the main settings file;SECRETS_FILE_FOR_HYDRO
: exact location of the file containing secrets;ENV_FOR_HYDRO
: the environment to load after loading thedefault
one (e.g.development
,testing
,staging
,production
, etc.). By default, Hydroconf will load thedevelopment
environment, unless otherwise specified.ENVVAR_PREFIX_FOR_HYDRO
: the prefix of the environement variables holding your configuration – see group number 2. above. By default it’sHYDRO
(note that you don’t have to include the_
separator, as that is added automatically);ENVVAR_NESTED_SEP_FOR_HYDRO
: the separator in the environment variables holding your configuration that signals a nesting point. By default it’s__
(double underscore), so if you setHYDRO_REDIS__HOST=localhost
, Hydroconf will match it with the nested fieldredis.host
in your configuration.
Hydroconf initialization
You can create a new Hydroconf struct in two ways.
The first one is to use the Hydroconf::default()
method, which will use the
default settings. The default constructor will attempt to load the settings
from the environment variables (those in the form *_FOR_HYDRO
), and if it
doesn’t find them it will use the default values. The alternative is to create
a HydroSettings
struct manually and pass it to Hydroconf
:
let hydro_settings = HydroSettings::default() .set_envvar_prefix("MYAPP".into()) .set_env("staging".into()); let hydro = Hydroconf::new(hydro_settings);
Note that HydroSettings::default()
will still try to load the settings from
the environment before you overwrite them.
The hydration process
1. Configuration loading
When you call Hydroconf::hydrate()
, Hydroconf starts looking for your
configuration files and if it finds them, it loads them. The search starts from
HydroSettings.root_path
; if the root path is not defined, Hydroconf will use
std::env::current_exe()
. From this path, Hydroconf generates all the possible
candidates by walking up the directory tree, also searching in the config
subfolder at each level. For example, if the root path is
/home/user/www/api-server/dist
, Hydroconf will try the following paths, in
this order:
/home/user/www/api-server/dist/config
/home/user/www/api-server/dist
/home/user/www/api-server/config
/home/user/www/api-server
/home/user/www/config
/home/user/www
/home/user/config
/home/user
/home/config
/home
/config
/
In each directory, Hydroconf will search for the files
settings.{toml,json,yaml,ini,hjson}
and
.secrets.{toml,json,yaml,ini,hjson}
. As soon as one of those (or both) are
found, the search stops and Hydroconf won’t search the remaining upper levels.
2. Merging
In this step, Hydroconf merges the values from the different environments
from the configuration files discovered in the previous step. Hydroconf
first checks if an environment called default
exists: in that case those
values are selected first. Then, it checks if the environment specified for
Hydroconf (ENV_FOR_HYDRO
, or “development” if not specified) exists and in
that case it selects those values and merges them with the existing ones.
3. .env
file overrides
In this step Hydroconf starts from the root path (the same one from step 1),
and walks the filesystem upward in search of an .env
file. If it finds
one, it parses it and merges those values with the existing ones.
4. Environment variables overrides
In this step Hydroconf merges the values from all environment variables that
you defined with the Hydro prefix (HYDRO_
by default, as explained in the
previous section).
5. Deserialization
Finally, Hydroconf tries to deserialize the configuration into the return type you specify, which should be your configuration struct.
Best practices
In order to keep your configuration simple, secure and effective, Hydroconf makes it easy for you to follow these best practices:
- keep the non-secret values inside
config/settings.{toml,yaml,json,...}
separated by environment; in particular, define a “default” environment which contains the base settings, and specialize it in all the additional environments that you need (e.g. “development”, “testing”, “staging”, “production”, etc.); - keep the secret values inside
config/.secrets.{toml,yaml,json,...}
separated by environment and exclude this file from version control; - define the environment variable
ENV_FOR_DYNACONF
to specify which environment should be loaded (besides the “default” one, which is always loaded first); - if you want to override some values, or specify some secret values which
are not in the secret file, define the environment variables
HYDRO_*
(or use a custom prefix and defineENVVAR_PREFIX_FOR_HYDRO
).
Structs
Config | A prioritized configuration repository. It maintains a set of configuration sources, fetches values to populate those, and provides them according to the source’s priority. |
Environment | |
File | |
FileSources | |
HydroSettings | |
Hydroconf |
Enums
ConfigError | Represents all possible errors that can occur when working with configuration. |