Konfiguration von Rust-Anwendungen: Bibliotheken config und dotenv
Jede moderne Anwendung benötigt ein flexibles Konfigurationssystem: Datenbankeinstellungen, API-Schlüssel, Server-Ports, Logging-Level und andere Parameter. Im Rust-Ökosystem gibt es dafür leistungsstarke Werkzeuge – die Crates config und dotenv. Sie ermöglichen es, Einstellungen aus verschiedenen Quellen (Dateien, Umgebungsvariablen, Kommandozeilenargumente) in einer einzigen typsicheren Struktur zu vereinen.
Warum eine separate Bibliothek?
Rust ist eine Sprache mit starker statischer Typisierung. Das einfache Lesen von Zeichenketten aus std::env::var() führt zu vielen manuellen Prüfungen und Umwandlungen. Die Bibliothek config automatisiert diesen Prozess:
- Unterstützung von Formaten: YAML, JSON, TOML, HJSON, INI, RON
- Hierarchische Einstellungsstruktur mit Überschreibungsmöglichkeit
- Automatische Deserialisierung in benutzerdefinierte Strukturen über
serde - Zusammenführung mehrerer Quellen mit Prioritäten (Datei < env < CLI)
Installation
Fügen Sie in Cargo.toml hinzu:
[dependencies]config = "0.14"serde = { version = "1.0", features = ["derive"] }dotenv = "0.15"Basisbeispiel: Lesen aus Datei und env
Erstellen wir eine Struktur für die Anwendungskonfiguration:
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> { // Konfiguration laden 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(())}Datei config/default.toml:
[server]host = "127.0.0.1"port = 8080workers = 4
[database]url = "postgres://localhost/mydb"pool_size = 10Umgebungsvariablen mit dem Präfix APP_ überschreiben die Werte aus der Datei. Beispielsweise ändert APP_DATABASE__URL die Datenbank-URL.
Arbeit mit dotenv
Für die Entwicklung wird oft die Datei .env verwendet. Das Crate dotenv lädt sie in die Umgebungsvariablen, bevor config initialisiert wird:
use dotenv::dotenv;
fn main() { dotenv().ok(); // .env laden // danach Initialisierung von config wie im obigen Beispiel}Inhalt von .env:
APP_SERVER__PORT=3000APP_DATABASE__POOL_SIZE=20Fortgeschrittenes Szenario: mehrere Quellen
Reale Projekte erfordern die Kombination von Einstellungen aus verschiedenen Orten. config ermöglicht es, eine Kette von Quellen mit Priorität festzulegen:
let config = Config::builder() // Basiseinstellungen (niedrige Priorität) .add_source(config::File::with_name("config/default")) // Überschreibung für die spezifische Umgebung .add_source(config::File::with_name(&format!("config/{}", env::var("APP_ENV").unwrap_or("development")))) // Umgebungsvariablen (mittlere Priorität) .add_source(config::Environment::with_prefix("APP")) // Kommandozeilenargumente (hohe Priorität) .add_source(config::File::from(std::env::args().nth(1).unwrap_or_default())) .build()?;Best Practices
- Verwenden Sie Präfixe für Umgebungsvariablen, um Konflikte mit Systemvariablen zu vermeiden