server_env_config/
conf.rs

1//! The [`Config`] struct represents a full server configuration.
2
3use crate::db::DbConfig;
4use crate::env::Environment;
5use crate::server::HttpServerConfig;
6use anyhow::Result;
7use log::{debug, log, Level};
8use std::fmt::Debug;
9
10/// `Config` is responsible of the configuration of a "full" server, reading the settings
11/// from environment variables: the deployment environment, the HTTP server settings
12/// and database settings.
13///
14/// Once you have the Rust objects with all the basic information you need for your server,
15/// like the database connection (`DATABASE_URL`), the deployment environment (`APP_ENV`)
16/// or the port where to start the app (`PORT`), you can use the struct objects
17/// to use those values to start up your Actix server, Rocket server, or whatever
18/// server your app use.
19#[derive(Debug, Clone)]
20pub struct Config {
21    /// The environment name chosen to run the app, normally
22    /// set through the environment variable `APP_ENV`.
23    /// See [`Environment::init()`].
24    pub env: Environment,
25    /// All the config needed to launch an HTTP server.
26    pub server: HttpServerConfig,
27    /// All the config needed to setup a database, regardless of the engine.
28    pub db: DbConfig,
29}
30
31impl Config {
32    /// Initialize all the configurations, setting each value with its corresponding
33    /// environment variable, e.g. the `env` attribute with the `APP_ENV` environment variable.
34    ///
35    /// The port number is get from the `PORT` env variable, otherwise
36    /// defaulted to `default_port`.
37    ///
38    /// # Examples
39    /// ```
40    /// use std::env;
41    /// use server_env_config::Config;
42    /// use server_env_config::env::Environment;
43    ///
44    /// // Configurations should be actually set by the OS environment
45    /// env::set_var("APP_ENV", "production");  // if not set, "local" is the default
46    /// env::set_var("APP_URI", "api/v1");
47    /// env::set_var("PORT", "8080");
48    /// env::set_var("DATABASE_URL", "postgresql://user:pass@localhost/db");
49    ///
50    /// let result = Config::init(9999);        // 9999 will be used if "PORT" is not set
51    /// assert!(result.is_ok());
52    /// let config = result.unwrap();
53    /// assert_eq!(config.env, Environment::Production);
54    /// assert_eq!(config.server.port, 8080);
55    /// assert_eq!(config.server.url, "http://127.0.0.1:8080/api/v1/");    // calculated field
56    /// assert_eq!(config.db.database_url, "postgresql://user:pass@localhost/db");
57    /// // Some settings have default values if env variables are not set
58    /// assert_eq!(config.db.min_connections, 1);
59    /// assert_eq!(config.db.max_connections, 10);
60    /// // The `to_string()` method prints out all variables in .env format
61    /// println!("{}", config.to_string());
62    /// // # APP_URL --> http://127.0.0.1:8080/api/v1/
63    /// // APP_URI="api/v1"
64    /// // HOST=127.0.0.1
65    /// // PORT=8080
66    /// // APP_ENV=production
67    /// // DATABASE_URL="postgresql://user:pass@localhost/db"
68    /// // MIN_CONNECTIONS=1
69    /// // ...
70    /// ```
71    pub fn init(default_port: u16) -> Result<Config> {
72        Self::init_for(default_port, None)
73    }
74
75    /// Initialize config with the environment passed, if `None`, env
76    /// will be set with the `APP_ENV` environment variable.
77    ///
78    /// The port number is get from the `PORT` env variable, otherwise
79    /// defaulted to `default_port`.
80    ///
81    /// See [`Config::init()`].
82    pub fn init_for(default_port: u16, environment: Option<Environment>) -> Result<Config> {
83        debug!("⚙️  Configuring app ...");
84        let env = match environment {
85            Some(e) => e,
86            None => Environment::init()?,
87        };
88        let log_level = match env {
89            Environment::Test => Level::Debug,
90            _ => Level::Info,
91        };
92        log!(log_level, "⚙️  Environment set to {env}");
93        let db = DbConfig::init_for(&env)?;
94        let server = HttpServerConfig::init_for("127.0.0.1", default_port)?;
95        Ok(Config { env, server, db })
96    }
97}
98
99impl ToString for Config {
100    /// This `to_string()` implementation prints out all the config
101    /// values in `.env` format, using as key the environment variable
102    /// used to set-up the config, even if the configuration was
103    /// set in another way, e.g. using a default value.
104    fn to_string(&self) -> String {
105        format!(
106r#"{}
107APP_ENV={}
108{}"#,
109            self.server.to_string(),
110            self.env,
111            self.db.to_string(),
112        )
113    }
114}