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}