inspirer_foundation/
error.rs

1#[cfg(feature = "enable-axum")]
2use axum::{http::StatusCode, response::IntoResponse, Json};
3use serde::Serialize;
4use std::fmt::{self, Debug, Display};
5
6pub type Result<T, E = Error> = std::result::Result<T, E>;
7
8/// 错误消息
9#[derive(Debug, Serialize)]
10pub struct ErrorMessage<S, T = ()>
11where
12    S: Display + Debug,
13    T: Serialize + Debug,
14{
15    #[serde(skip)]
16    pub status: StatusCode,
17    pub code: u32,
18    pub msg: S,
19    pub data: T,
20}
21
22/// 错误消息模板
23pub type ErrorMessageTemplate = ErrorMessage<&'static str, ()>;
24
25impl<S, T> std::error::Error for ErrorMessage<S, T>
26where
27    S: Serialize + Display + Debug,
28    T: Serialize + Debug,
29{
30}
31
32impl<S, T> fmt::Display for ErrorMessage<S, T>
33where
34    S: Serialize + Display + Debug,
35    T: Serialize + Debug,
36{
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "{}", self.msg)
39    }
40}
41
42impl<S, T> IntoResponse for ErrorMessage<S, T>
43where
44    S: Serialize + Display + Debug,
45    T: Serialize + Debug,
46{
47    fn into_response(self) -> axum::response::Response {
48        (self.status, Json(self)).into_response()
49    }
50}
51
52#[macro_export]
53macro_rules! define_inspirer_error {
54    ($name:ident, $status:expr, $code:literal, $msg:literal) => {
55        pub const $name: $crate::ErrorMessageTemplate = ErrorMessageTemplate { status: $status, code: $code, msg: $msg, data: () };
56    };
57}
58
59define_inspirer_error!(UNKONWN_ERROR, StatusCode::INTERNAL_SERVER_ERROR, 1, "System internal error.");
60
61#[derive(Debug, thiserror::Error)]
62pub enum Error {
63    #[error("Extract Service extension error.")]
64    ExtractServiceExtensionFailed,
65    #[error("Get configuration data failed.")]
66    GetConfigurationFailedError,
67    #[error("Get configuration component failed.")]
68    GetConfigurationComponentFailed,
69    #[error(transparent)]
70    ConfigError(#[from] config::ConfigError),
71    #[error(transparent)]
72    DatabaseError(#[from] sea_orm::DbErr),
73    #[error(transparent)]
74    InspirerWebApplicationErrorMessage(#[from] ErrorMessageTemplate),
75    #[error(transparent)]
76    ValidateError(#[from] validator::ValidationErrors),
77    #[error(transparent)]
78    AxumJsonRejection(#[from] axum::extract::rejection::JsonRejection),
79    #[error(transparent)]
80    AxumFormRejection(#[from] axum::extract::rejection::FormRejection),
81    #[error(transparent)]
82    AxumQueryRejection(#[from] axum::extract::rejection::QueryRejection),
83    #[error("System internal error.")]
84    UnknownError,
85}
86
87#[cfg(feature = "enable-axum")]
88impl IntoResponse for Error {
89    fn into_response(self) -> axum::response::Response {
90        let (code, status) = match self {
91            Self::UnknownError => (1, StatusCode::INTERNAL_SERVER_ERROR),
92            Self::ExtractServiceExtensionFailed => (2, StatusCode::INTERNAL_SERVER_ERROR),
93            Self::GetConfigurationFailedError => (3, StatusCode::INTERNAL_SERVER_ERROR),
94            Self::GetConfigurationComponentFailed => (4, StatusCode::INTERNAL_SERVER_ERROR),
95            Self::ConfigError(_) => (5, StatusCode::INTERNAL_SERVER_ERROR),
96            Self::DatabaseError(_) => (6, StatusCode::INTERNAL_SERVER_ERROR),
97            Self::AxumFormRejection(_)
98            | Self::AxumJsonRejection(_)
99            | Self::AxumQueryRejection(_) => {
100                return ErrorMessage {
101                    code: 7,
102                    msg: "请求参数解析错误",
103                    data: Option::<()>::None,
104                    status: StatusCode::BAD_REQUEST,
105                }
106                .into_response();
107            }
108            Self::ValidateError(err) => {
109                return ErrorMessage {
110                    code: 8,
111                    msg: "请求参数错误",
112                    data: err.errors(),
113                    status: StatusCode::BAD_REQUEST,
114                }
115                .into_response();
116            }
117            Self::InspirerWebApplicationErrorMessage(msg) => return msg.into_response(),
118        };
119
120        ErrorMessage {
121            status,
122            code,
123            msg: format!("{}", self),
124            data: Option::<()>::None,
125        }
126        .into_response()
127    }
128}