config.rs (3689B)
1 //! Configuration management for the orders service 2 //! 3 //! This module handles loading and parsing configuration from multiple sources: 4 //! 1. config.toml file (base configuration) 5 //! 2. Environment variables prefixed with `ORDERS_` (overrides) 6 //! 7 //! # Environment Variables 8 //! - `ORDERS_SERVER_PORT` - Override server port 9 //! - `ORDERS_DATABASE_URL` - Override database connection string 10 //! - `ORDERS_DATABASE_MAX_CONNECTIONS` - Override max database connections 11 //! 12 //! # Example config.toml 13 //! ```toml 14 //! [server] 15 //! port = 3003 16 //! 17 //! [database] 18 //! url = "postgres://user:pass@localhost:5432/dbname" 19 //! max_connections = 10 20 //! ``` 21 22 use anyhow::Result; 23 use serde::Deserialize; 24 25 /// Root configuration structure 26 /// 27 /// Loaded from config.toml and can be overridden with environment variables. 28 #[derive(Debug, Deserialize, Clone)] 29 pub struct Config { 30 /// Server configuration (port) 31 pub server: ServerConfig, 32 33 /// Database connection configuration 34 pub database: DatabaseConfig, 35 36 /// Microservices configuration 37 pub services: ServicesConfig, 38 39 /// HTTP client configuration 40 pub http_client: HttpClientConfig, 41 } 42 43 /// Server configuration 44 #[derive(Debug, Deserialize, Clone)] 45 pub struct ServerConfig { 46 /// Port to bind the HTTP server to (default: 3003) 47 pub port: u16, 48 } 49 50 /// Database connection configuration 51 #[derive(Debug, Deserialize, Clone)] 52 pub struct DatabaseConfig { 53 /// PostgreSQL connection string 54 /// Format: postgres://user:password@host:port/database 55 pub url: String, 56 57 /// Maximum number of connections in the connection pool 58 /// Recommended: 5-20 for most applications 59 pub max_connections: u32, 60 } 61 62 /// Microservices configuration 63 #[derive(Debug, Deserialize, Clone)] 64 pub struct ServicesConfig { 65 /// Products service host 66 pub products_host: String, 67 /// Products service port 68 pub products_port: u16, 69 /// Inventory service host 70 pub inventory_host: String, 71 /// Inventory service port 72 pub inventory_port: u16, 73 } 74 75 impl ServicesConfig { 76 /// Get the full products service URL 77 pub fn products_service_url(&self) -> String { 78 format!("http://{}:{}", self.products_host, self.products_port) 79 } 80 81 /// Get the full inventory service URL 82 pub fn inventory_service_url(&self) -> String { 83 format!("http://{}:{}", self.inventory_host, self.inventory_port) 84 } 85 } 86 87 /// HTTP client configuration 88 #[derive(Debug, Deserialize, Clone)] 89 pub struct HttpClientConfig { 90 /// Request timeout in seconds 91 pub timeout_secs: u64, 92 } 93 94 impl Config { 95 /// Load configuration from config.toml and environment variables 96 /// 97 /// Configuration is loaded in this order (later sources override earlier ones): 98 /// 1. config.toml in the current directory 99 /// 2. Environment variables with `ORDERS_` prefix 100 /// 101 /// # Example Environment Override 102 /// ```bash 103 /// export ORDERS_SERVER_PORT=8080 104 /// export ORDERS_DATABASE_URL=postgres://localhost/mydb 105 /// ``` 106 /// 107 /// # Errors 108 /// Returns an error if: 109 /// - config.toml is not found or invalid 110 /// - Required fields are missing 111 /// - Environment variable format is invalid 112 pub fn load() -> Result<Self> { 113 let config = config::Config::builder() 114 // Load from config.toml file 115 .add_source(config::File::with_name("config")) 116 // Override with environment variables (e.g., ORDERS_SERVER_PORT) 117 .add_source(config::Environment::with_prefix("ORDERS")) 118 .build()?; 119 120 // Deserialize into our Config struct 121 let config: Config = config.try_deserialize()?; 122 Ok(config) 123 } 124 }