Configuración de aplicaciones Rust: bibliotecas config y dotenv
Cualquier aplicación moderna requiere un sistema de configuración flexible: ajustes de base de datos, claves API, puertos del servidor, niveles de registro y otros parámetros. En el ecosistema de Rust existen herramientas potentes para esto: los crates config y dotenv. Permiten combinar configuraciones de diferentes fuentes (archivos, variables de entorno, argumentos de línea de comandos) en una única estructura type-safe.
¿Por qué se necesita una biblioteca separada?
Rust es un lenguaje con tipado estático fuerte. Leer cadenas simples de std::env::var() conduce a múltiples verificaciones y transformaciones manuales. La biblioteca config automatiza este proceso:
- Soporte de formatos: YAML, JSON, TOML, HJSON, INI, RON
- Estructura jerárquica de configuraciones con posibilidad de anulación
- Deserialización automática en estructuras personalizadas a través de
serde - Combinación de múltiples fuentes con prioridades (archivo < env < CLI)
Instalación
Agregue en Cargo.toml:
[dependencies]config = "0.14"serde = { version = "1.0", features = ["derive"] }dotenv = "0.15"Ejemplo básico: lectura desde archivo y env
Creemos una estructura para la configuración de la aplicación:
use serde::Deserialize;use config::Config;
#[derive(Debug, Deserialize)]struct AppConfig { server: ServerConfig, database: DatabaseConfig,}
#[derive(Debug, Deserialize)]struct ServerConfig { host: String, port: u16, workers: u8,}
#[derive(Debug, Deserialize)]struct DatabaseConfig { url: String, pool_size: u32,}
fn main() -> Result<(), config::ConfigError> { // Cargamos la configuración let config = Config::builder() .add_source(config::File::with_name("config/default")) .add_source(config::Environment::with_prefix("APP")) .build()?;
let app_config: AppConfig = config.try_deserialize()?; println!("{:#?}", app_config); Ok(())}Archivo config/default.toml:
[server]host = "127.0.0.1"port = 8080workers = 4
[database]url = "postgres://localhost/mydb"pool_size = 10Las variables de entorno con el prefijo APP_ anulan los valores del archivo. Por ejemplo, APP_DATABASE__URL cambiará la URL de la base de datos.
Trabajo con dotenv
Para mayor comodidad en el desarrollo, a menudo se usa el archivo .env. El crate dotenv lo carga en las variables de entorno antes de inicializar config:
use dotenv::dotenv;
fn main() { dotenv().ok(); // cargamos .env // luego inicialización de config como en el ejemplo anterior}Contenido de .env:
APP_SERVER__PORT=3000APP_DATABASE__POOL_SIZE=20Escenario avanzado: múltiples fuentes
Los proyectos reales requieren combinar configuraciones de diferentes lugares. config permite definir una cadena de fuentes con prioridad:
let config = Config::builder() // Configuraciones base (baja prioridad) .add_source(config::File::with_name("config/default")) // Anulación para un entorno específico .add_source(config::File::with_name(&format!("config/{}", env::var("APP_ENV").unwrap_or("development")))) // Variables de entorno (prioridad media) .add_source(config::Environment::with_prefix("APP")) // Argumentos de línea de comandos (alta prioridad) .add_source(config::File::from(std::env::args().nth(1).unwrap_or_default())) .build()?;Best Practices
- Use prefijos para las variables de entorno, para evitar conflictos con variables del sistema
También en la biblioteca
Cliente Elasticsearch para Swift (iOS/macOS) — guía completa
Caché en C# (.NET): Redis, MemoryCache y otras soluciones
gRPC para C# (.NET): bibliotecas, configuración y ejemplos de código