config-rs

repository·main·Indexed 25 days ago

https://github.com/rust-cli/config-rs

A layered configuration system for Rust applications (v0.15.25) that supports merging defaults, environment variables, and files in formats such as JSON, TOML, YAML, RON, INI, JSON5, and Corn. It features a ConfigBuilder for managing synchronous and asynchronous sources, nested access via JSONPath-style keys, and integration with serde for deserializing configuration into Rust structs.

Tokens
4.3K
Snippets
2
Records
35
Agent score
85%

What's inside config-rs

  1. Overview of config-rs

    main

    config-rs is a layered configuration system for Rust applications designed with support for 12-factor application principles. It allows you to build configuration by layering different sources, such as setting defaults, programmatically overriding values, reading from various file formats, and pulling from environment variables.

    Key capabilities:

    • Layered Configuration: Combine defaults, explicit values, files, and environment variables.
    • Loosely Typed: Values can be read into any supported type that has a reasonable conversion.
    • Nested Access: Access nested fields using a subset of JSONPath, supporting child (redis.port) and subscript (databases[0].name) operators.
    • Read-Only: Note that this library is designed for reading configuration; it cannot be used to write changed values back to configuration files.
  2. Configure supported file formats via feature flags

    main

    To use specific file formats with config-rs, you must enable the corresponding feature flags in your Cargo.toml. By default, only a minimal set of features may be active. Enable the following flags to add support for specific formats:

    • ini: Support for INI files
    • json: Support for JSON files
    • yaml: Support for YAML files
    • toml: Support for TOML files
    • ron: Support for RON files
    • json5: Support for JSON5 files
    • corn: Support for Corn files
  3. Layer configuration sources in config-rs

    main

    The Config system allows merging several types of sources to build a final configuration object. Supported sources include:

    • Environment variables: Using the Environment source.
    • String literals: Using FileSourceString in well-known formats.
    • Files: Using FileSourceFile in well-known formats or custom formats defined via the Format trait.
    • Other Config instances: Merging an existing Config object.
    • Manual overrides: Using ConfigBuilder::set_override for programmatic control.
  4. Configure the Environment source

    main

    The Environment struct allows you to collect environment variables into your configuration hierarchy. You can use it to map environment variables (like APP_DATABASE_URL) to configuration keys (like database.url).

    Key features include:

    • Prefixing: Limit the source to variables starting with a specific prefix (e.g., APP_).
    • Separators: Define how nested keys are represented (e.g., using _ to represent . in configuration).
    • Type Parsing: Automatically attempt to parse values as booleans, integers, or floats.
    • Case Conversion: Transform keys to specific casing (e.g., kebab-case) using the convert-case feature.
  5. Use ConfigBuilder to layer configuration sources

    main

    The ConfigBuilder allows you to register multiple configuration sources in a specific order to build a final Config object. The layering order is:

    1. Defaults: Loaded first via set_default. These can be overwritten by any other source.
    2. Sources: Loaded in the order they are added via add_source or add_async_source. These can be external files, environment variables, etc.
    3. Overrides: Loaded last via set_override. These cannot be overwritten by any other source.

    Note that adding sources does not perform I/O; I/O only occurs when build() or build_cloned() is called.

  6. Extend config-rs with custom formats

    main
    If you need to support a custom, proprietary, or less common data format, you can implement the Format trait. Once implemented, your custom format can be integrated seamlessly into the existing config-rs APIs.
  7. Mock environment variables for testing

    main

    Instead of relying on the actual system environment variables, you can provide a custom map to the Environment source. This is useful for unit testing configuration logic without side effects.

    # use config::{Environment, Config};
    # use serde::Deserialize;
    # use std::collections::HashMap;
    # use std::convert::TryInto;
    # use config::error::Result;
    
    #[test]
    fn test_config() -> Result<(), config::ConfigError> {
      #[derive(Clone, Debug, Deserialize)]
      struct MyConfig {
        pub my_string: String,
      }
    
      let mut env = HashMap::new();
      env.insert("MY_STRING".into(), "my-value".into());
    
      let source = Environment::default()
        .source(Some(env));
    
      let config: MyConfig = Config::builder()
        .add_source(source)
        .build()?
        .try_into()?;
    
      assert_eq!(config.my_string, "my-value");
    
      Ok(())
    }
  8. Create a configuration source from a file path

    main

    You can create a File source using a file path or a base name.

    • Use File::new(name, format) to create a required file source with a specific format.
    • Use File::with_name(base_name) to create a required file source that attempts to automatically discover the format based on registered file extensions.
    • Use From<&Path> or From<PathBuf> to convert an existing path into a File<FileSourceFile, FileFormat> source.
  9. Set configuration defaults and overrides

    main

    You can explicitly set values in the builder using keys (which are parsed as Expression).

    • set_default(key, value): Sets a value that can be overwritten by any subsequent source or override.
    • set_override(key, value): Sets a value that will not be altered by any defaults, sources, or async sources.
    • set_override_option(key, value): Sets an override only if the provided value is Some.
  10. Configure file requirement and format for a File source

    main

    When building a File source, you can chain methods to customize its behavior:

    • .format(format): Explicitly sets the file format (must implement FileStoredFormat).
    • .required(bool): Sets whether the configuration building process should error if the file is missing. If set to false, a missing file will result in an empty configuration map instead of an error.
  11. Convert configuration values using `Value` methods

    main

    The Value struct represents a single configuration entry. It provides several into_* methods to attempt to convert the underlying configuration data into specific Rust types. These methods perform type checking and can handle certain implicit conversions (e.g., converting truthy strings like "yes" or "on" to booleans, or rounding floats to integers).

    Available conversion methods:

    • into_bool(): Returns bool. Accepts booleans, non-zero numbers, and strings like "true", "on", or "yes".
    • into_int(): Returns i64. Accepts signed/unsigned integers, booleans, floats (rounded), and specific truthy/falsy strings.
    • into_int128(): Returns i128.
    • into_uint(): Returns u64.
    • into_uint128(): Returns u128.
    • into_float(): Returns f64.
    • into_string(): Returns String.
    • into_array(): Returns Vec<Value>.
    • into_table(): Returns Map<String, Value>.

    All conversion methods return a Result<T>, which will return a ConfigError if the type is incompatible.