Crate confgr

Crate confgr 

Source
Expand description

§Overview

The Config derive macro simplifies application configuration by automatically loading settings from various sources in the following order:

  1. Environment Variables.
  2. Configuration File (e.g., toml, json, yaml, ini, ron, json5).
  3. Default Values.

§Key Features

  • Simplicity: Minimal boilerplate. Define your configuration struct, customize the macro, and you’re good to go.
  • Flexibility: Supports a variety of configuration file formats including toml, json, yaml, ini, ron, and json5.
  • Integration: Synergy with other crates, such as smart_default.

There are also several useful helper attributes for customizing the behavior of the derive macro.

AttributeFunctionality
prefixSets a prefix for environment variables. Can be applied at the struct or field level.
pathSpecifies the static path to a configuration file. The file extension may (though probably shouldn’t) be omitted.
env_pathResolves an environment variable at runtime to determine the configuration file path.
default_pathSpecifies a fallback path used if the path determined by env_path does not exist.
keyOverrides the default environment variable name. This ignores the prefix and uses the provided key directly.
nameforwards to #[serde(rename = "_")] to rename fields during serialization/deserialization. It does not affect environment variable names.
nestRequired for non-standard types which must also derive Config, used for nesting configuration structs.
skipSkips loading the attribute from an environment variable. Necessary for types that don’t implement FromStr but are present in the configuration file.
separatorSpecifies a character to separate the prefix and the field name. The default separator is “_”.

§Path Attribute Behavior

  • env_path: Resolves the provided environment variable into configuration filepath. This takes precedence over path and default_path, but will not panic if the file or environment does not exist.

  • path: Directly sets the path to the configuration file. When set, default_path may not be used. Panics if the file does not exist.

  • default_path: Identical to path, but does not panic if the file does not exist.

§Usage


serde is a required dependency.

[dependencies]
confgr = "0.2.0"
serde = { version = "1.0", features = ["derive"] }

Then define your configuration like so:

use confgr::prelude::*;

#[derive(Config)]
#[config(path = "docs.toml", prefix = "APP")]
pub struct AppConfig {
    port: u32,
    address: String,
    #[config(key = "DEBUG_MODE")]
    debug: bool,
}

// Default implementation is required.
impl Default for AppConfig {
    fn default() -> Self {
        Self {
            port: 3000,
            address: "127.0.0.1".to_string(),
            debug: false
        }
    }
}

std::env::set_var("APP_PORT", "4000");
std::env::set_var("DEBUG_MODE", "true");

let settings = AppConfig::load_config();


assert_eq!(settings.port, 4000);
assert_eq!(settings.address, "127.0.0.1");
assert!(settings.debug)

§Warnings/Pitfalls

  • Nested structs do not load separate files based on their own path attributes. If you would like multiple files to be loaded, you must use multiple structs with multiple load_config() calls. This may change in a future version.
  • Types that do not implement FromStr must use #[config(skip)] or #[config(nest)].
  • The separator character is only inserted between the prefix and the field name, not in any part of the parsed field name.
  • The prefix is applied per field or for the entire struct, but is ignored if #[config(key = "_")] is used.
  • All configuration structs must implement Default.
  • Types used in configuration structs must implement Deserialize, Clone, Debug and Default.
  • Option is not currently compatible with #[config(nest)] on types that implement Confgr.

§Debugging

When encountering issues using the macro, the following methods may be of use.

§Verifying Environment Variables

The get_env_keys() method can be used to retrieve the resolved environment variable keys based on the struct’s configuration.

use std::collections::HashMap;
use confgr::prelude::*;

#[derive(Config, Default)]
#[config(prefix = "APP")]
pub struct AppConfig {
    port: u32,
    #[config(separator = "__")]
    address: String,
    #[config(key = "DEBUG_MODE")]
    debug: bool,
}

let keys: HashMap<String, String> = AppConfig::get_env_keys();

assert_eq!(keys["port"], "APP_PORT");
assert_eq!(keys["address"], "APP__ADDRESS");
assert_eq!(keys["debug"], "DEBUG_MODE");

§Verifying Configuration File Path

You can use check_file() to ensure that the configuration file is accessible the path specified or resolved in the path, or env_path attribute.

use confgr::prelude::*;

#[derive(Config, Default)]
#[config(path = "docs.toml", env_path = "APP_CONFIG_FILE")]
pub struct AppConfig {
    port: u32,
    debug: bool,
}

std::env::set_var("APP_CONFIG_FILE", "env_config.toml");
AppConfig::check_file().expect("Failed to open configuration file.");

std::env::remove_var("APP_CONFIG_FILE");
AppConfig::check_file().expect("Failed to open configuration file.");

§Test Deserialization

The deserialize_from_file() method can be used to manually test the config deserialization step. This will give you the parsed configuration struct before default values are applied.

use confgr::prelude::*;

#[derive(Config, Default)]
#[config(path = "docs.toml")]
pub struct AppConfig {
    port: u32,
    debug: bool,
}

let config = AppConfig::deserialize_from_file().expect("Failed to deserialize configuration.");
println!("Deserialized configuration: {:?}", config);

Modules§

core
Traits and types consumed by the Config derive macro. Re-export from confgr_core.
derive
Derive macro for the Confgr trait. Re-export from confgr_derive.
prelude
Macro and trait exports for convenience.