#parser #env-var #utility

envoke

A simple and ergonomic way to load environment variables into struct fields

12 releases

0.3.0 Mar 26, 2025
0.2.2 Mar 11, 2025
0.1.7 Mar 3, 2025
0.1.6 Feb 27, 2025

#174 in Configuration

Download history 519/week @ 2025-02-21 377/week @ 2025-02-28 412/week @ 2025-03-07 168/week @ 2025-03-14 240/week @ 2025-03-21 56/week @ 2025-03-28

909 downloads per month

MIT/Apache

44KB
473 lines

envoke

Envoke is a simple and ergonomic way to load environment variables into struct fields with minimal setup. With support for multiple ways to define environment variables with additional fallbacks, default values, custom parsing, validation, and nested structs for a cleaner interface.

Designed to be flexible and reduce boilerplate, all to make it easier to manage environment variables in your application.

Whats new?

  • This list!
  • Load environment variables from a .env file with the dotenv attribute—works on both structs and enums.
  • The new try_parse_fn attribute lets you use fallible parsing functions. Just like parse_fn, but it accepts a Result.

Read more here!

Key features

  • Flexible Environment Variable Naming
    Customize naming conventions with support for multiple environments, renaming, prefixes, and suffixes.

  • Versatile Default Values
    Define defaults through type-based values, direct assignments, or function return values.

  • Pre-Assignment Parsing
    Convert values into complex types before field assignment for enhanced data handling.

  • Comprehensive Validation
    Validate values before and/or after assignment to ensure data integrity.

  • Structured Data Support
    Seamlessly work with nested structs, enums, or standalone enums.

  • Built-in Sequence & Map Parsing
    Effortlessly parse sequence and map-formatted strings for structured data.

Usage

Add to your Cargo.toml

[dependencies]
envoke = "0.3.0"

Example

use std::time::Duration;

use anyhow::Context;
use envoke::{Envoke, Error, Fill};

#[derive(Debug, Fill)]
#[fill(rename_all = "SCREAMING_SNAKE_CASE")]
struct Prod {
    #[fill(env)]
    api_port: u16,
}

#[derive(Debug, Fill)]
#[fill(rename_all = "SCREAMING_SNAKE_CASE")]
struct Development {
    #[fill(env)]
    api_port: u16,
}

#[derive(Debug, Fill)]
#[fill(rename_all = "UPPERCASE")]
enum Mode {
    Production(Production),
    Development(Development),
}

fn above_thirty(secs: &u64) -> anyhow::Result<()> {
    if *secs < 30 {
        anyhow::bail!("connect timeout cannot be less than 30 seconds, found {secs} second(s)")
    }

    Ok(())
}

fn to_duration(secs: u64) -> Duration {
  Duration::from_secs(secs)
}

#[derive(Debug, Fill)]
#[fill(rename_all = "SCREAMING_SNAKE_CASE")]
struct Environment {
    #[fill(nested)]
    mode: Mode,

    #[fill(env, default = Duration::from_secs(30))]
    #[fill(parse_fn = to_duration, arg_type = u64, validate_fn(before = above_thirty))]
    connect_timeout: Duration,
}

fn main() -> anyhow::Result<()> {
    let env =
        Environment::try_envoke().with_context(|| "An error occurred while loading environment");

    ...
}

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~0.7–1.2MB
~23K SLoC