Expand description

Figment figment::Provider for optionally file-based env config values.

use serde::Deserialize;
use figment::{Figment, providers::{Env, Format, Toml}};
use figment_file_provider_adapter::FileAdapter;

#[derive(Deserialize)]
struct Config {
  frobnicate: String,
  foo: u64,
}

let config: Config = Figment::new()
    .merge(FileAdapter::wrap(Env::prefixed("APP_")))
    .merge(FileAdapter::wrap(Toml::file("config.toml")))
    .extract()?;

Overview

This crate contains the FileAdapter provider for figment, to allow loading configuration values from either environment variables or files. This is especially useful for secret management in combination with containers.

For instance, to pass an API key to the configuration, you could use either the config value API_KEY=abc123deadbeef, or you could write that API key to a file /secrets/api_key and pass the config value API_KEY_FILE=/secrets/api_key.

Note that if both are specified, the non-_FILE one wins.

Recommendations

Environment variables namespacing

The provider will try to read any config value with a key that ends with _FILE (or the custom suffix) and will error if the file cannot be read. As such, for environment variables, it is usually necessary to have a namespace in the form of a unique prefix, to avoid conficts or unexpected interactions: FileAdapter::wrap(Env::prefixed("MY_APP_")) (see [figment::providers::Env::prefixed]).

Since it is built on top of [figment::providers::Env], you can set it up so that only some variables accept the _FILE variant and the rest are read normally with FileAdapter::only:

let file_keys = ["foo", "bar"];
let env = Env::prefixed("APP_");
// Call `.only` on the FileAdapter, not the Env.
let config: Config = Figment::new()
    .merge(FileAdapter::wrap(env.clone()).only(&file_keys))
    .merge(env.ignore(&file_keys))
    .extract()?;

Similarly for other providers, you can usually merge with and without the wrapper to restrict the wrapper to some keys only:

let file_keys = ["foo", "bar"];
let config: Config = Figment::new()
    .merge(FileAdapter::wrap(Toml::file("config.toml")).only(&file_keys))
    .merge(Toml::file("config.toml"))
    .extract()?;

Changing the suffix

You can also specify the suffix to use. For instance, to use “_PATH” instead of “_FILE”:

let config: Config = Figment::new()
    .merge(FileAdapter::wrap(Env::prefixed("APP_")).with_suffix("_PATH"))
    .extract()?;

Structs