ServiceConf

Derive Macro ServiceConf 

Source
#[derive(ServiceConf)]
{
    // Attributes available to this derive:
    #[conf]
}
Expand description

ServiceConf derive macro

Automatically implements the from_env() method on structs for loading configuration from environment variables.

§Supported Attributes

§Struct-level Attributes

§#[conf(prefix = "PREFIX_")]

Add a prefix to all environment variable names in the struct.

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
#[conf(prefix = "MYAPP_")]
struct Config {
    pub api_key: String,  // Reads from MYAPP_API_KEY
    pub port: u16,        // Reads from MYAPP_PORT
}

§Field-level Attributes

§#[conf(name = "CUSTOM_NAME")]

Override the default environment variable name for a specific field.

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
struct Config {
    #[conf(name = "DATABASE_URL")]
    pub db_connection: String,  // Reads from DATABASE_URL
}

§#[conf(default)]

Use Default::default() when the environment variable is not set.

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
struct Config {
    #[conf(default)]
    pub port: u16,  // Uses 0 if PORT not set
}

§#[conf(default = value)]

Use an explicit default value when the environment variable is not set.

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
struct Config {
    #[conf(default = 8080)]
    pub port: u16,  // Uses 8080 if PORT not set
}

§#[conf(from_file)]

Support loading from file-based secrets (Kubernetes/Docker Secrets). Reads from both VAR_NAME and VAR_NAME_FILE environment variables.

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
struct Config {
    #[conf(from_file)]
    pub api_key: String,  // Reads from API_KEY or API_KEY_FILE
}

§#[conf(deserializer = "function")]

Use a custom deserializer function for complex types.

The function signature must be: fn(&str) -> Result<T, impl std::fmt::Display>

Can be combined with default to provide a fallback value, or used with Option<T> to make the field optional:

use serviceconf::ServiceConf;
use std::time::Duration;

fn parse_duration_secs(s: &str) -> Result<Duration, String> {
    s.parse::<u64>()
        .map(Duration::from_secs)
        .map_err(|e| format!("Failed to parse: {}", e))
}

#[derive(ServiceConf)]
struct Config {
    // Required field with custom deserializer
    #[conf(deserializer = "parse_duration_secs")]
    pub timeout: Duration,

    // With default value (uses default when env var is not set)
    #[conf(deserializer = "parse_duration_secs", default = Duration::from_secs(60))]
    pub retry_interval: Duration,

    // With Option<T> (None when env var is not set)
    #[conf(deserializer = "parse_duration_secs")]
    pub max_timeout: Option<Duration>,
}

§Examples

Basic usage:

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
struct Config {
    pub api_key: String,

    #[conf(default = 8080)]
    pub port: u16,
}

fn main() -> anyhow::Result<()> {
    let config = Config::from_env()?;
    Ok(())
}

With prefix and file-based secrets:

use serviceconf::ServiceConf;

#[derive(ServiceConf)]
#[conf(prefix = "APP_")]
struct Config {
    #[conf(from_file)]
    pub database_password: String,  // Reads from APP_DATABASE_PASSWORD or APP_DATABASE_PASSWORD_FILE

    #[conf(default = 3000)]
    pub port: u16,  // Reads from APP_PORT, defaults to 3000
}

With custom deserializer and default:

use serviceconf::ServiceConf;
use std::time::Duration;

fn parse_duration_secs(s: &str) -> Result<Duration, String> {
    s.parse::<u64>()
        .map(Duration::from_secs)
        .map_err(|e| e.to_string())
}

fn parse_comma_list(s: &str) -> Result<Vec<String>, String> {
    Ok(s.split(',').map(|s| s.trim().to_string()).collect())
}

#[derive(ServiceConf)]
struct Config {
    // Custom deserializer with explicit default value
    #[conf(deserializer = "parse_duration_secs", default = Duration::from_secs(30))]
    pub timeout: Duration,

    // Custom deserializer with Default::default()
    #[conf(deserializer = "parse_comma_list", default)]
    pub allowed_hosts: Vec<String>,
}

// Uses default values when environment variables are not set
std::env::remove_var("TIMEOUT");
std::env::remove_var("ALLOWED_HOSTS");
let config = Config::from_env().unwrap();
assert_eq!(config.timeout, Duration::from_secs(30));
assert_eq!(config.allowed_hosts, Vec::<String>::new());

// Override with environment variables
std::env::set_var("TIMEOUT", "60");
std::env::set_var("ALLOWED_HOSTS", "localhost, example.com");
let config = Config::from_env().unwrap();
assert_eq!(config.timeout, Duration::from_secs(60));
assert_eq!(config.allowed_hosts, vec!["localhost", "example.com"]);

For complete documentation and more examples, see the serviceconf crate.