1use axum::Json;
16use axum::http::{HeaderValue, StatusCode, header};
17use axum::response::{IntoResponse, Response};
18use serde::{Deserialize, Serialize};
19use std::ops::{Deref, DerefMut};
20
21#[derive(Debug, Default, Serialize, Deserialize, Clone)]
23pub struct ErrorData {
24 pub sub_category: Option<String>,
26 pub code: Option<String>,
28 pub exception: Option<bool>,
30 pub extra: Option<Vec<String>>,
32}
33
34#[derive(Serialize)]
36struct ErrorSerialize<'a> {
37 category: &'a str,
38 message: &'a str,
39 #[serde(flatten)]
40 data: &'a ErrorData,
41}
42
43#[derive(Deserialize)]
45struct ErrorDeserialize {
46 #[serde(default)]
47 category: String,
48 #[serde(default)]
49 message: String,
50 #[serde(flatten)]
51 data: ErrorData,
52}
53
54#[derive(Debug, Clone, Default)]
60pub struct Error {
61 pub status: u16,
63 pub category: String,
65 pub message: String,
67 data: Box<ErrorData>,
68}
69
70impl std::fmt::Display for Error {
71 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
72 write!(f, "{}", self.message)
73 }
74}
75
76impl std::error::Error for Error {}
77
78impl Serialize for Error {
80 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
81 where
82 S: serde::Serializer,
83 {
84 ErrorSerialize {
85 category: &self.category,
86 message: &self.message,
87 data: &self.data,
88 }
89 .serialize(serializer)
90 }
91}
92
93impl<'de> Deserialize<'de> for Error {
94 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
95 where
96 D: serde::Deserializer<'de>,
97 {
98 let d = ErrorDeserialize::deserialize(deserializer)?;
99 Ok(Self {
100 status: 0,
101 category: d.category,
102 message: d.message,
103 data: Box::new(d.data),
104 })
105 }
106}
107
108impl Deref for Error {
111 type Target = ErrorData;
112 fn deref(&self) -> &Self::Target {
113 &self.data
114 }
115}
116
117impl DerefMut for Error {
118 fn deref_mut(&mut self) -> &mut Self::Target {
119 &mut self.data
120 }
121}
122
123impl Error {
124 #[must_use]
126 pub fn new(message: impl ToString) -> Self {
127 Self {
128 message: message.to_string(),
129 ..Default::default()
130 }
131 }
132
133 #[must_use]
135 pub fn with_category(mut self, category: impl ToString) -> Self {
136 self.category = category.to_string();
137 self
138 }
139
140 #[must_use]
142 pub fn with_sub_category(mut self, sub_category: impl ToString) -> Self {
143 self.sub_category = Some(sub_category.to_string());
144 self
145 }
146
147 #[must_use]
149 pub fn with_code(mut self, code: impl ToString) -> Self {
150 self.code = Some(code.to_string());
151 self
152 }
153
154 #[must_use]
156 pub fn with_status(mut self, status: u16) -> Self {
157 self.status = status;
158 self
159 }
160
161 #[must_use]
163 pub fn with_exception(mut self, exception: bool) -> Self {
164 self.exception = Some(exception);
165 self
166 }
167
168 #[must_use]
170 pub fn add_extra(mut self, value: impl ToString) -> Self {
171 self.extra
172 .get_or_insert_with(Vec::new)
173 .push(value.to_string());
174 self
175 }
176}
177
178impl IntoResponse for Error {
180 fn into_response(self) -> Response {
181 let status = StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
182 let mut res = (status, Json(&self)).into_response();
184 res.extensions_mut().insert(self);
185 res.headers_mut()
186 .insert(header::CACHE_CONTROL, HeaderValue::from_static("no-cache"));
187 res
188 }
189}