backend/src/config.rs
Description
Module de configuration structurée de l’application backend. Fournit une struct Config qui centralise tous les paramètres de configuration chargés depuis les variables d’environnement.
Note
Ce fichier définit une structure de configuration, mais n’est actuellement pas utilisé dans main.rs.
Le fichier main.rs charge les variables d’environnement directement.
Responsabilités
Centralisation de la configuration - Regroupe tous les paramètres dans une seule structure - Type-safety avec Rust
Chargement depuis l’environnement - Lecture des variables d’environnement - Valeurs par défaut pour le développement - Validation des types (parsing)
Structures
Config
Signature:
#[derive(Debug, Clone)]
pub struct Config {
pub database_url: String,
pub jwt_secret: String,
pub server_host: String,
pub server_port: u16,
}
Description:
Structure contenant toute la configuration de l’application.
Champs:
Champ |
Type |
Description |
|---|---|---|
|
|
URL de connexion à PostgreSQL (format: |
|
|
Clé secrète pour signer les tokens JWT (minimum 256 bits recommandés) |
|
|
Adresse IP d’écoute du serveur HTTP (ex: “127.0.0.1”, “0.0.0.0”) |
|
|
Port d’écoute du serveur HTTP (ex: 8080, 3000) |
Traits dérivés:
Debug- Permet l’affichage avec{:?}pour le debuggingClone- Permet de cloner la configuration si nécessaire
Méthodes
from_env()
Signature:
pub fn from_env() -> Self
Description:
Constructeur qui charge la configuration depuis les variables d’environnement.
Variables d’environnement lues:
Variable |
Obligatoire |
Comportement |
|---|---|---|
|
✅ Oui |
Panic si absente avec message: “DATABASE_URL must be set” |
|
✅ Oui |
Panic si absente avec message: “JWT_SECRET must be set” |
|
❌ Non |
Défaut: |
|
❌ Non |
Défaut: |
Comportement:
Lit chaque variable d’environnement
Pour les variables obligatoires: panic si absentes
Pour les variables optionnelles: utilise valeur par défaut
Parse
SERVER_PORTenu16, panic si invalide
Retour:
Instance de Config avec tous les champs initialisés.
Exemple d’utilisation:
use koprogo_api::config::Config;
use dotenv::dotenv;
#[actix_web::main]
async fn main() {
dotenv().ok();
// Charge la configuration
let config = Config::from_env();
println!("Server will start on {}:{}", config.server_host, config.server_port);
println!("Database: {}", config.database_url);
}
Cas d’erreur:
// ❌ DATABASE_URL absente
// Panic: "DATABASE_URL must be set"
// ❌ JWT_SECRET absente
// Panic: "JWT_SECRET must be set"
// ❌ SERVER_PORT non numérique (ex: "abc")
// Panic: "SERVER_PORT must be a valid number"
Avantages de cette approche
Type Safety
// ✅ Le port est toujours un u16 valide let port: u16 = config.server_port; // ❌ Pas de parsing manuel partout // let port = env::var("SERVER_PORT").parse::<u16>().unwrap();
Validation centralisée
Toutes les erreurs de configuration détectées au démarrage
Pas de surprise en cours d’exécution
Documentation des dépendances
Les champs de la struct documentent les variables nécessaires
Facile de voir toute la configuration d’un coup d’œil
Facilité de test
#[cfg(test)] mod tests { use super::*; fn test_config() -> Config { Config { database_url: "postgres://test:test@localhost/test_db".to_string(), jwt_secret: "test-secret-key".to_string(), server_host: "127.0.0.1".to_string(), server_port: 8080, } } }
Utilisation actuelle vs. potentielle
Approche actuelle (main.rs)
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let jwt_secret = env::var("JWT_SECRET")
.unwrap_or_else(|_| "super-secret-key-change-in-production".to_string());
let server_host = env::var("SERVER_HOST")
.unwrap_or_else(|_| "127.0.0.1".to_string());
let server_port = env::var("SERVER_PORT")
.unwrap_or_else(|_| "8080".to_string())
.parse::<u16>()
.expect("SERVER_PORT must be a valid number");
Approche avec Config
use koprogo_api::config::Config;
let config = Config::from_env();
let pool = create_pool(&config.database_url).await?;
let auth_use_cases = AuthUseCases::new(user_repo, config.jwt_secret);
HttpServer::new(move || { /* ... */ })
.bind((config.server_host.as_str(), config.server_port))?
.run()
.await
Recommandation
Tip
Pour améliorer le code:
Utiliser
Config::from_env()dansmain.rsau lieu de variables séparéesPasser
&ConfigouArc<Config>aux composants qui en ont besoinFacilite l’ajout de nouvelles variables de configuration
Améliorations possibles
Support fichiers de configuration
impl Config { pub fn from_file(path: &str) -> Result<Self, ConfigError> { // Charger depuis config.toml ou config.yaml } }
Validation métier
impl Config { pub fn validate(&self) -> Result<(), ConfigError> { if self.jwt_secret.len() < 32 { return Err(ConfigError::JwtSecretTooShort); } if self.server_port < 1024 { return Err(ConfigError::PrivilegedPort); } Ok(()) } }
Environnements multiples
#[derive(Debug, Clone)] pub enum Environment { Development, Staging, Production, } impl Config { pub fn environment(&self) -> Environment { match env::var("ENV").as_deref() { Ok("production") => Environment::Production, Ok("staging") => Environment::Staging, _ => Environment::Development, } } }
Fichier .env exemple
# Database
DATABASE_URL=postgres://koprogo:koprogo123@localhost:5432/koprogo_db
# JWT Secret (générer avec: openssl rand -base64 32)
JWT_SECRET=votre-cle-secrete-super-forte-ici
# Server
SERVER_HOST=127.0.0.1
SERVER_PORT=8080
# Environment
ENV=development
Dépendances
std::env- Accès aux variables d’environnement
Fichiers associés
backend/src/main.rs- Utilise les variables d’environnement directementbackend/.env- Fichier de variables d’environnement localdocker-compose.yml- Variables d’environnement pour Docker