gonfig 0.1.12

A unified configuration management library for Rust that seamlessly integrates environment variables, config files, and CLI arguments
Documentation
use gonfig::{ConfigBuilder, Environment, MergeStrategy};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Serialize, Deserialize)]
struct AppConfig {
    app_name: String,
    version: String,
    features: Features,
    databases: HashMap<String, DatabaseConfig>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Features {
    auth_enabled: bool,
    rate_limiting: bool,
    max_requests_per_minute: u32,
}

#[derive(Debug, Serialize, Deserialize)]
struct DatabaseConfig {
    host: String,
    port: u16,
    username: String,
    #[serde(skip_serializing)]
    #[allow(dead_code)]
    password: Option<String>,
}

fn main() -> gonfig::Result<()> {
    std::env::set_var("APP_APP_NAME", "MyApp");
    std::env::set_var("APP_VERSION", "2.0.0");
    std::env::set_var("APP_FEATURES_AUTH_ENABLED", "true");
    std::env::set_var("APP_FEATURES_RATE_LIMITING", "true");
    std::env::set_var("APP_FEATURES_MAX_REQUESTS_PER_MINUTE", "100");
    std::env::set_var("APP_DATABASES_PRIMARY_HOST", "primary.db.local");
    std::env::set_var("APP_DATABASES_PRIMARY_PORT", "5432");
    std::env::set_var("APP_DATABASES_PRIMARY_USERNAME", "admin");
    std::env::set_var("APP_DATABASES_PRIMARY_PASSWORD", "secret123");

    let env = Environment::new()
        .with_prefix("APP")
        .separator("_")
        .case_sensitive(false);

    let builder = ConfigBuilder::new()
        .with_merge_strategy(MergeStrategy::Deep)
        .with_file_optional("examples/config.toml")?
        .add_source(Box::new(env))
        .with_cli()
        .validate_with(|value| {
            if let Some(features) = value.get("features") {
                if let Some(max_req) = features.get("max_requests_per_minute") {
                    if let Some(max_req_num) = max_req.as_u64() {
                        if max_req_num == 0 {
                            return Err(gonfig::Error::Validation(
                                "max_requests_per_minute must be greater than 0".into(),
                            ));
                        }
                    }
                }
            }
            Ok(())
        });

    let value = builder.build_value()?;

    match serde_json::from_value::<AppConfig>(value.clone()) {
        Ok(config) => {
            println!("Loaded configuration:");
            println!("App: {} v{}", config.app_name, config.version);
            println!("\nFeatures:");
            println!("  Auth enabled: {}", config.features.auth_enabled);
            println!("  Rate limiting: {}", config.features.rate_limiting);
            println!(
                "  Max requests/min: {}",
                config.features.max_requests_per_minute
            );

            println!("\nDatabases:");
            for (name, db) in &config.databases {
                println!(
                    "  {}: {}:{} (user: {})",
                    name, db.host, db.port, db.username
                );
            }
        }
        Err(e) => eprintln!("Configuration error: {e}"),
    }
    println!("\nRaw merged configuration:");
    match serde_json::to_string_pretty(&value) {
        Ok(json_str) => println!("{json_str}"),
        Err(e) => eprintln!("Failed to serialize to JSON: {e}"),
    }

    Ok(())
}