Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

kellpossible/toml-env

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

27 Commits

Repository files navigation

toml-env

crates.io docs.rs GitHub Workflow Status (with event)

A simple configuration library using toml.

This library is designed to load a configuration for an application at startup using the initialize() function. The configuration can be loaded (in order of preference):

  1. From a dotenv style file .env.toml (a file name of your choosing)
  2. From an environment variable CONFIG (or a variable name of your choosing).
  3. From mapped environments (e.g. MY_VARIABLE => my_variable.child).
  4. From a configuration file.

Why yet another config library?

Here are some possible alternatives to this library:

  • config You want maximum flexibility.
  • figment You want maximum flexibility.
  • just-config You want maximum flexibility.
  • dotenvy You just want .env support.
  • env_inventory You just want environment variable configuration file support.

Why would you use this one?

  • Small opinionated feature set.
  • Minimal dependencies.
  • .env using TOML which is a more established file format standard.
  • Loading config from environment variables using custom mappings into the configuration (MY_VARIABLE => child.child.config) in a json pointer style (full syntax is not supported).
  • Loading config from environment variables using automatic mappings, which are configurable. (MY_APP__PARENT__CHILD => parent.child)
  • Loading config from TOML stored in a multiline environment variable.
    • For large configurations with nested maps, this could be seen as a bit more legible than MY_VARIABLE__SOMETHING_ELSE__SOMETHING_SOMETHING_ELSE.
    • You can also just copy text from a TOML file to use in the environment variable instead of translating it into complicated names of variables.

Config Struct

Firstly you need to define your struct which implements serde::de::DeserializeOwned + serde::Serialize + Default:

#[derive(serde::Serialize, serde::Deserialize, Default)]
struct Config {
 config_value_1: String,
 config_value_2: String,
 config_child: ConfigChild
}
#[derive(serde::Serialize, serde::Deserialize, Default)]
struct ConfigChild {
 config_value_3: String,
}

.env.toml

Initally configuration will attempted to be loaded from a file named .env.toml by default. You can elect to customize the name of this file. The format of this file is as follows:

SECRET_ENV_VAR_1="some value"
SECRET_ENV_VAR_2="some other value"
[CONFIG]
config_value_1="some value"
config_value_2="some other value"
[CONFIG.config_child]
config_value_3="some other other value"

Environment variables for the application can be set using the top level keys in the file (e.g. SECRET_ENV_VAR_1).

The configuration can be loaded from a subset of this file in CONFIG. The CONFIG key will be the name from the Args::config_variable_name which is CONFIG by default.

Environment Variable CONFIG

You can specify the configuration by storing it in the variable name as specified using Args::config_variable_name (CONFIG by default).

# Store a multiline string into an environment variable in bash shell.
read -r -d '' CONFIG << EOM
config_value_1="some value"
config_value_2="some other value"

[config_child]
config_value_3="some other other value"
EOM

Example

CONFIG Variable

A simple example loading configuration from CONFIG, using the default settings.

use serde::{Deserialize, Serialize};
use toml_env::{initialize, Args};
#[derive(Serialize, Deserialize)]
struct Config {
 value_1: String,
 value_2: bool,
}
// Normally you may choose set this from a shell script or some
// other source in your environment (docker file or server config file).
std::env::set_var(
 "CONFIG",
 r#"
value_1="Something from CONFIG environment"
value_2=true
"#,
);
let config: Config = initialize(Args::default())
 .unwrap()
 .unwrap();
assert_eq!(config.value_1, "Something from CONFIG environment");
assert_eq!(config.value_2, true);

Custom Variable Mappings

A simple demonstration of the custom environment variable mappings:

use serde::{Deserialize, Serialize};
use toml_env::{Args, initialize, TomlKeyPath};
use std::str::FromStr;
#[derive(Serialize, Deserialize)]
struct Config {
 value_1: String,
 value_2: bool,
}
// Normally you may choose set this from a shell script or some
// other source in your environment (docker file or server config file).
std::env::set_var("VALUE_1", "Hello World");
std::env::set_var("VALUE_2", "true");
let config: Config = initialize(Args {
 map_env: [
 ("VALUE_1", "value_1"),
 ("VALUE_2", "value_2"),
 ]
 .into_iter()
 .map(|(key, value)| {
 (key, TomlKeyPath::from_str(value).unwrap())
 }).collect(),
 ..Args::default()
})
 .unwrap()
 .unwrap();
assert_eq!(config.value_1, "Hello World");
assert_eq!(config.value_2, true);

Automatic Variable Mappings

A simple demonstration of the automatic environment variable mappings:

use serde::{Deserialize, Serialize};
use toml_env::{Args, initialize, AutoMapEnvArgs};
// NOTE: the `deny_unknown_fields` can be used to reject
// mappings which don't conform to the current spec.
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct Config {
 value_1: String,
 value_2: bool,
}
// Normally you may choose set this from a shell script or some
// other source in your environment (docker file or server config file).
std::env::set_var("CONFIG__VALUE_1", "Hello World");
std::env::set_var("CONFIG__VALUE_2", "true");
let config: Config = initialize(Args {
 auto_map_env: Some(AutoMapEnvArgs::default()),
 // The default prefix is CONFIG.
 // In practice you would usually use a custom prefix:
 // prefix: Some("MY_APP"),
 ..Args::default()
})
 .unwrap()
 .unwrap();
assert_eq!(config.value_1, "Hello World");
assert_eq!(config.value_2, true);

.env.toml File

A simple example loading configuration and environment variables from .env.toml, using the default settings.

use serde::{Deserialize, Serialize};
use toml_env::{Args, initialize};
#[derive(Serialize, Deserialize)]
struct Config {
 value_1: String,
 value_2: bool,
}
let dir = tempfile::tempdir().unwrap();
std::env::set_current_dir(&dir).unwrap();
let dotenv_path = dir.path().join(".env.toml");
// Normally you would read this from .env.toml file
std::fs::write(
 &dotenv_path,
 r#"
OTHER_VARIABLE="hello-world"
[CONFIG]
value_1="Something from .env.toml"
value_2=true
"#,
)
.unwrap();
let config: Config = initialize(Args::default())
 .unwrap()
 .unwrap();
assert_eq!(config.value_1, "Something from .env.toml");
assert_eq!(config.value_2, true);
let secret = std::env::var("OTHER_VARIABLE").unwrap();
assert_eq!(secret, "hello-world");

All Features

A more complex example demonstrating all the features.

use serde::{Deserialize, Serialize};
use tempfile::tempdir;
use toml_env::{Args, initialize, Logging, TomlKeyPath, AutoMapEnvArgs};
use std::str::FromStr;
#[derive(Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
struct Config {
 value_1: String,
 value_2: bool,
 child: Child,
 array: Vec<String>,
}
#[derive(Serialize, Deserialize, Default)]
#[serde(deny_unknown_fields)]
struct Child {
 value_3: i32,
 value_4: u8,
 value_5: String,
 value_6: String,
}
let dir = tempdir().unwrap();
let dotenv_path = dir.path().join(".env.toml");
let config_path = dir.path().join("config.toml");
// Normally you would read this from .env.toml file
std::fs::write(
 &dotenv_path,
 r#"
SECRET="hello-world"
[MY_CONFIG]
value_1="Something from .env.toml"
[MY_CONFIG.child]
value_3=-5
value_4=16
"#,
)
.unwrap();
// Normally you may choose set this from a shell script or some
// other source in your environment (docker file or server config file).
std::env::set_var(
 "MY_CONFIG",
 r#"
value_1="Something from MY_CONFIG environment"
value_2=true
"#,
);
std::env::set_var(
 "VALUE_1",
 "Something from Environment"
);
std::env::set_var(
 "VALUE_5",
 "Something from Environment"
);
std::env::set_var(
 "MY_APP__CHILD__VALUE_6",
 "Something from Environment"
);
std::env::set_var(
 "MY_APP__ARRAY__1",
 "Hello"
);
std::env::set_var(
 "MY_APP__ARRAY__0",
 "Hello"
);
// Normally you would read this from config.toml
// (or whatever name you want) file.
std::fs::write(
 &config_path,
 r#"
value_1="Something from config.toml"
value_2=false
[child]
value_4=45
"#,
)
.unwrap();
let config: Config = initialize(Args {
 dotenv_path: &dotenv_path,
 config_path: Some(&config_path),
 config_variable_name: "MY_CONFIG",
 logging: Logging::StdOut,
 map_env: [
 ("VALUE_1", "value_1"),
 ("VALUE_5", "child.value_5"),
 ("VALUE_99", "does.not.exist"),
 ]
 .into_iter()
 .map(|(key, value)| {
 (key, TomlKeyPath::from_str(value).unwrap())
 }).collect(),
 auto_map_env: Some(AutoMapEnvArgs {
 divider: "__",
 prefix: Some("MY_APP"),
 transform: Box::new(|name| name.to_lowercase()),
 })
})
 .unwrap()
 .unwrap();
assert_eq!(config.value_1, "Something from .env.toml");
assert_eq!(config.value_2, true);
assert_eq!(config.array[0], "Hello");
assert_eq!(config.child.value_3, -5);
assert_eq!(config.child.value_4, 16);
assert_eq!(config.child.value_5, "Something from Environment");
let secret = std::env::var("SECRET").unwrap();
assert_eq!(secret, "hello-world");

Changelog

See CHANGELOG.md for an account of changes to this library.

About

A simple configuration library using TOML

Resources

License

Stars

Watchers

Forks

Packages

Contributors

Languages

AltStyle によって変換されたページ (->オリジナル) /