From c4746970a24b1592c6029807bd64ac803074c76d Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Sat, 25 Apr 2026 03:04:25 +0300 Subject: [PATCH] feat: Add DatabaseError variant and improve error response handling - Add DatabaseError(String) variant to ChargingError enum - Add DatabaseError case to log_error helper with error-level logging - Add DatabaseError Display implementation - Refactor IntoResponse to use generic error messages instead of detailed strings - Add detail field to error responses containing full error message via to_string() - Change RedisConnection status code from INTERNAL_SERVER_ERROR to SERVICE_UNAVAILABLE --- apps/charging-engine/src/errors/helpers.rs | 3 +++ apps/charging-engine/src/errors/types.rs | 28 ++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/apps/charging-engine/src/errors/helpers.rs b/apps/charging-engine/src/errors/helpers.rs index fd95fc0..4134fd1 100644 --- a/apps/charging-engine/src/errors/helpers.rs +++ b/apps/charging-engine/src/errors/helpers.rs @@ -126,6 +126,9 @@ pub fn log_error(error: &ChargingError) { ChargingError::RedisOperation(msg) => { tracing::error!("Redis operation error: {}", msg); } + ChargingError::DatabaseError(msg) => { + tracing::error!("Database error: {}", msg); + } ChargingError::SubscriberNotFound(imsi) => { tracing::warn!("Subscriber not found: {}", imsi); } diff --git a/apps/charging-engine/src/errors/types.rs b/apps/charging-engine/src/errors/types.rs index 62ac253..d0b2acd 100644 --- a/apps/charging-engine/src/errors/types.rs +++ b/apps/charging-engine/src/errors/types.rs @@ -7,6 +7,7 @@ use std::fmt; pub enum ChargingError { RedisConnection(String), RedisOperation(String), + DatabaseError(String), SubscriberNotFound(String), RatingPlanNotFound(String), InsufficientCredit { available: u64, requested: u64 }, @@ -21,6 +22,7 @@ impl fmt::Display for ChargingError { match self { ChargingError::RedisConnection(msg) => write!(f, "Redis connection error: {}", msg), ChargingError::RedisOperation(msg) => write!(f, "Redis operation error: {}", msg), + ChargingError::DatabaseError(msg) => write!(f, "Database error: {}", msg), ChargingError::SubscriberNotFound(imsi) => write!(f, "Subscriber not found: {}", imsi), ChargingError::RatingPlanNotFound(plan_id) => write!(f, "Rating plan not found: {}", plan_id), ChargingError::InsufficientCredit { available, requested } => { @@ -38,22 +40,22 @@ impl std::error::Error for ChargingError {} impl IntoResponse for ChargingError { fn into_response(self) -> Response { - let (status, error_message) = match self { - ChargingError::RedisConnection(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg), - ChargingError::RedisOperation(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg), - ChargingError::SubscriberNotFound(imsi) => (StatusCode::NOT_FOUND, format!("Subscriber not found: {}", imsi)), - ChargingError::RatingPlanNotFound(plan_id) => (StatusCode::NOT_FOUND, format!("Rating plan not found: {}", plan_id)), - ChargingError::InsufficientCredit { available, requested } => { - (StatusCode::PAYMENT_REQUIRED, format!("Insufficient credit: available={}, requested={}", available, requested)) - } - ChargingError::UsageBlocked(reason) => (StatusCode::FORBIDDEN, reason), - ChargingError::InvalidInput(msg) => (StatusCode::BAD_REQUEST, msg), - ChargingError::SerializationError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg), - ChargingError::InternalError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg), + let (status, message) = match &self { + ChargingError::RedisConnection(_) => (StatusCode::SERVICE_UNAVAILABLE, "Redis connection error"), + ChargingError::RedisOperation(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Redis operation error"), + ChargingError::DatabaseError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Database error"), + ChargingError::SubscriberNotFound(_) => (StatusCode::NOT_FOUND, "Subscriber not found"), + ChargingError::RatingPlanNotFound(_) => (StatusCode::NOT_FOUND, "Rating plan not found"), + ChargingError::InsufficientCredit { .. } => (StatusCode::PAYMENT_REQUIRED, "Insufficient credit"), + ChargingError::UsageBlocked(_) => (StatusCode::FORBIDDEN, "Usage blocked"), + ChargingError::InvalidInput(_) => (StatusCode::BAD_REQUEST, "Invalid input"), + ChargingError::SerializationError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Serialization error"), + ChargingError::InternalError(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Internal error"), }; let body = json!({ - "error": error_message + "error": message, + "detail": self.to_string(), }); (status, axum::Json(body)).into_response()