Spaces:
Paused
Paused
| use axum::http::StatusCode; | |
| use axum::response::{IntoResponse, Response}; | |
| use serde::Serialize; | |
| use serde_json::json; | |
| pub struct ErrorPayload { | |
| pub status: String, | |
| pub code: String, | |
| pub message: String, | |
| pub details: Option<serde_json::Value>, | |
| } | |
| pub fn error_payload( | |
| message: &str, | |
| code: &str, | |
| details: Option<serde_json::Value>, | |
| ) -> serde_json::Value { | |
| let mut payload = json!({ | |
| "status": "error", | |
| "code": code, | |
| "message": message, | |
| }); | |
| if let Some(d) = details { | |
| payload["details"] = d; | |
| } | |
| payload | |
| } | |
| pub struct AppError { | |
| pub status_code: StatusCode, | |
| pub body: serde_json::Value, | |
| } | |
| impl AppError { | |
| pub fn new(status_code: StatusCode, message: &str, code: &str) -> Self { | |
| Self { | |
| status_code, | |
| body: json!({ "detail": error_payload(message, code, None) }), | |
| } | |
| } | |
| pub fn with_details( | |
| status_code: StatusCode, | |
| message: &str, | |
| code: &str, | |
| details: serde_json::Value, | |
| ) -> Self { | |
| Self { | |
| status_code, | |
| body: json!({ "detail": error_payload(message, code, Some(details)) }), | |
| } | |
| } | |
| } | |
| impl IntoResponse for AppError { | |
| fn into_response(self) -> Response { | |
| (self.status_code, axum::Json(self.body)).into_response() | |
| } | |
| } | |
| pub fn http_error(status_code: StatusCode, message: &str, code: &str) -> AppError { | |
| AppError::new(status_code, message, code) | |
| } | |
| // --- Typed error handling --- | |
| pub enum AppErrorKind { | |
| Database( rusqlite::Error), | |
| Pool( r2d2::Error), | |
| Telegram(String), | |
| Http( reqwest::Error), | |
| Config(String), | |
| Other(String), | |
| } | |
| impl From<AppErrorKind> for AppError { | |
| fn from(kind: AppErrorKind) -> Self { | |
| let (status_code, code) = match &kind { | |
| AppErrorKind::Database(_) | AppErrorKind::Pool(_) => { | |
| (StatusCode::INTERNAL_SERVER_ERROR, "database_error") | |
| } | |
| AppErrorKind::Telegram(_) => (StatusCode::BAD_GATEWAY, "telegram_error"), | |
| AppErrorKind::Http(_) => (StatusCode::BAD_GATEWAY, "http_error"), | |
| AppErrorKind::Config(_) => (StatusCode::SERVICE_UNAVAILABLE, "config_error"), | |
| AppErrorKind::Other(_) => (StatusCode::INTERNAL_SERVER_ERROR, "internal_error"), | |
| }; | |
| AppError::new(status_code, &kind.to_string(), code) | |
| } | |
| } | |