mehcode / config-rs

⚙️ Layered configuration system for Rust applications (with strong support for 12-factor applications).
Apache License 2.0
2.43k stars 206 forks source link

How do I use environment variables in configuration file? #447

Closed dev-davexoyinbo closed 11 months ago

dev-davexoyinbo commented 11 months ago

How do I use environment variables in configuration file?

database_configuration:
  postgres_host: ${postgres_host}
  postgres_port: 5432
  postgres_user: admin
  postgres_password: password123
  postgres_db: rust_jwt_authentication

I keep getting the postgres host as the string "${postgres_host}" instead of the value postgres_host from the .env file

matthiasbeyer commented 11 months ago

This crate does not support such functionality. You should use a templating library like handlebars for that!

dev-davexoyinbo commented 11 months ago

Thanks for the suggestion, I've been able to rewrite it to do that

use std::collections::HashMap;

use config::{Config, ConfigError, File, FileFormat};

#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct AppConfiguration {
    database_configuration: DatabaseConfiguration,
}

impl AppConfiguration {
    pub fn get_configuration() -> Result<AppConfiguration, ConfigError> {
        let base_path = std::env::current_dir().expect("Failed to determine the current directory");
        let configuration_path = base_path.join("configurations");

        let env_string = std::fs::read_to_string(".env").unwrap_or("".to_string());
        let environment_data: HashMap<String, String> = Config::builder()
            .add_source(File::from_str(&env_string, FileFormat::Ini))
            .build()?
            .try_deserialize()?;

        let handlebars = handlebars::Handlebars::new();
        let template_string = std::fs::read_to_string(configuration_path.join("base.yaml"))
            .expect("Unable to open configuration file");

        let rendered = handlebars
            .render_template(&template_string, &environment_data)
            .expect("Unable to render template");

        let builder = Config::builder()
            .add_source(File::from_str(rendered.as_str(), FileFormat::Yaml).required(true));

        return builder.build()?.try_deserialize();
    }
}

#[derive(serde::Deserialize, serde::Serialize, Debug)]
pub struct DatabaseConfiguration {
    postgres_host: String,
    postgres_port: u32,
    postgres_user: String,
    postgres_password: String,
    postgres_db: String,
}

configuration/base.yaml

database_configuration:
  postgres_host: {{postgres_host}}
  postgres_port: {{postgres_port}}
  postgres_user:  {{postgres_user}}
  postgres_password:  {{postgres_password}}
  postgres_db:  {{postgres_db}}

.env

postgres_host=127.0.0.1
postgres_port=6500
postgres_user=admin
postgres_password=password123
postgres_db=rust_jwt_authentication

main.rs

  let app_configurations = AppConfiguration::get_configuration().expect("Unable to build configuration");
  println!("{:?}", app_configurations);