fbc_starter/
error.rs

1use axum::{
2    http::StatusCode,
3    response::{IntoResponse, Response},
4    Json,
5};
6use serde_json::json;
7use thiserror::Error;
8
9/// 应用错误类型
10#[derive(Error, Debug)]
11pub enum AppError {
12    #[error("内部服务器错误: {0}")]
13    Internal(#[from] anyhow::Error),
14
15    #[error("未找到资源")]
16    NotFound,
17
18    #[error("未授权访问")]
19    Unauthorized,
20
21    #[error("禁止访问")]
22    Forbidden,
23
24    #[error("请求参数错误: {0}")]
25    BadRequest(String),
26
27    #[error("配置错误: {0}")]
28    Config(#[from] config::ConfigError),
29
30    /// 数据库错误(需要启用 database 特性)
31    #[cfg(feature = "database")]
32    #[error("数据库错误: {0}")]
33    Database(#[from] sqlx::Error),
34
35    /// 数据库连接池未初始化错误
36    #[cfg(feature = "database")]
37    #[error("数据库连接池未初始化")]
38    DatabaseNotInitialized,
39
40    /// Redis 错误(需要启用 redis 特性)
41    #[cfg(feature = "redis")]
42    #[error("Redis 错误: {0}")]
43    Redis(#[from] redis::RedisError),
44
45    /// Redis 客户端未初始化错误
46    #[cfg(feature = "redis")]
47    #[error("Redis 客户端未初始化")]
48    RedisNotInitialized,
49}
50
51/// 应用结果类型
52pub type AppResult<T> = Result<T, AppError>;
53
54impl IntoResponse for AppError {
55    fn into_response(self) -> Response {
56        let (status, error_message) = match self {
57            AppError::NotFound => (StatusCode::NOT_FOUND, self.to_string()),
58            AppError::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()),
59            AppError::Forbidden => (StatusCode::FORBIDDEN, self.to_string()),
60            AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
61            AppError::Config(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
62            #[cfg(feature = "database")]
63            AppError::Database(e) => {
64                tracing::error!("数据库错误: {:?}", e);
65                (
66                    StatusCode::INTERNAL_SERVER_ERROR,
67                    format!("数据库错误: {}", e),
68                )
69            }
70            #[cfg(feature = "database")]
71            AppError::DatabaseNotInitialized => {
72                tracing::error!("数据库连接池未初始化");
73                (
74                    StatusCode::INTERNAL_SERVER_ERROR,
75                    "数据库连接池未初始化".to_string(),
76                )
77            }
78            #[cfg(feature = "redis")]
79            AppError::Redis(e) => {
80                tracing::error!("Redis 错误: {:?}", e);
81                (
82                    StatusCode::INTERNAL_SERVER_ERROR,
83                    format!("Redis 错误: {}", e),
84                )
85            }
86            #[cfg(feature = "redis")]
87            AppError::RedisNotInitialized => {
88                tracing::error!("Redis 客户端未初始化");
89                (
90                    StatusCode::INTERNAL_SERVER_ERROR,
91                    "Redis 客户端未初始化".to_string(),
92                )
93            }
94            AppError::Internal(e) => {
95                tracing::error!("内部错误: {:?}", e);
96                (
97                    StatusCode::INTERNAL_SERVER_ERROR,
98                    "内部服务器错误".to_string(),
99                )
100            }
101        };
102
103        let body = Json(json!({
104            "error": error_message,
105            "status": status.as_u16(),
106        }));
107
108        (status, body).into_response()
109    }
110}