webserver_rs/web_core/
http_error.rs

1use salvo::prelude::*;
2
3use serde_json::Value;
4
5/// The unified error process for HTTP. Using macros `json_err` and `html_err` to conveniently return errors
6pub type HttpResult<T> = Result<T, AnyHttpError>;
7
8#[allow(dead_code)]
9pub enum HttpErrorKind {
10    Json(Value),
11    Html(String),
12}
13
14pub struct AnyHttpError(pub(crate) Option<StatusCode>, pub(crate) HttpErrorKind);
15
16impl AnyHttpError {
17    /// Construct an `AnyHttpError` by an HTTP status code and a specific error message
18    #[allow(dead_code)]
19    pub fn new(code: u16, msg: HttpErrorKind) -> Self {
20        Self(
21            Some(StatusCode::from_u16(code).unwrap_or(StatusCode::BAD_REQUEST)),
22            msg,
23        )
24    }
25    /// Construct an `AnyHttpError` by only a specific error message
26    /// HTTP status is context-dependent
27    pub fn new_msg(msg: HttpErrorKind) -> Self {
28        Self(None, msg)
29    }
30}
31
32#[async_trait]
33impl Writer for AnyHttpError {
34    async fn write(mut self, _req: &mut Request, _depot: &mut Depot, res: &mut Response) {
35        res.status_code(self.0.unwrap_or(StatusCode::BAD_REQUEST));
36        match self.1 {
37            HttpErrorKind::Json(v) => res.render(Text::Json(v.to_string())),
38            HttpErrorKind::Html(v) => res.render(Text::Html(v)),
39        }
40    }
41}
42
43/// Respond to clients an error with JSON data structure
44/// 1. Specify HTTP status code and the response data
45/// > json_err!(code, data)
46///
47/// 2. Just specify the response data, the HTTP status code is context-dependent
48/// > json_err!(data)
49#[macro_export]
50macro_rules! json_err {
51	($status:expr, {$($t:tt)*}) => {
52		{
53			use $crate::web_core::http_error;
54			http_error::AnyHttpError::new($status,http_error::HttpErrorKind::Json($crate::serde_json::json!({$($t)*})))
55		}
56	};
57	({$($t:tt)*}) => {
58		{
59			use $crate::web_core::http_error;
60			http_error::AnyHttpError::new_msg(http_error::HttpErrorKind::Json($crate::serde_json::json!({$($t)*})))
61		}
62	};
63}
64
65/// Respond to clients an error with html structure string
66/// A similar usage as `json_err`
67#[macro_export]
68macro_rules! html_err {
69    ($status:expr, $text:expr) => {{
70        use $crate::web_core::http_error;
71        http_error::AnyHttpError::new($status, http_error::HttpErrorKind::Html($text.into()))
72    }};
73    ($text:expr) => {{
74        use $crate::web_core::http_error;
75        http_error::AnyHttpError::new_msg(http_error::HttpErrorKind::Html($text.into()))
76    }};
77}