whynot_errors/
app_error.rs1use std::fmt::Display;
2
3use axum::http::StatusCode;
4use axum::response::{Html, IntoResponse, Response};
5use axum::Json;
6
7#[derive(Debug)]
10pub struct AppError {
11 pub code: StatusCode,
12 pub message: String,
13}
14
15impl Display for AppError {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(f, "Code: {}; {};", self.code.as_u16(), self.message)
18 }
19}
20
21impl AppError {
22 pub fn new(obj: impl ToString) -> Self {
25 Self {
26 code: StatusCode::INTERNAL_SERVER_ERROR,
27 message: obj.to_string(),
28 }
29 }
30
31 #[deprecated]
33 pub fn from(obj: impl ToString) -> Self {
34 Self {
35 code: StatusCode::INTERNAL_SERVER_ERROR,
36 message: obj.to_string(),
37 }
38 }
39
40 pub fn code<T: ToString>(code: StatusCode) -> impl Fn(T) -> Self {
42 move |obj| Self {
43 code,
44 message: obj.to_string(),
45 }
46 }
47}
48
49impl IntoResponse for AppError {
50 fn into_response(self) -> Response {
51 (self.code, self.message).into_response()
52 }
53}
54
55pub type AppResult<T> = Result<T, AppError>;
57
58pub type JsonResult<T> = AppResult<Json<T>>;
60
61pub fn json_ok<T>(obj: T) -> JsonResult<T> {
63 Ok(Json(obj))
64}
65
66pub type HtmlResult = AppResult<Html<String>>;
68
69pub fn html_ok(s: impl ToString) -> HtmlResult {
71 Ok(Html(s.to_string()))
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn test_fmt() {
80 let err = AppError {
81 code: StatusCode::OK,
82 message: "ok".to_string(),
83 };
84
85 assert_eq!(err.to_string(), "Code: 200; ok;");
86 }
87
88 #[test]
90 fn test_from() {
91 let err2: AppError = AppError::new("hi");
92
93 assert_eq!(err2.message, "hi");
94 assert_eq!(err2.code, StatusCode::INTERNAL_SERVER_ERROR);
95 }
96
97 #[test]
99 fn test_json() {
100 let resp: JsonResult<String> = json_ok("hi".to_string());
101 assert_eq!(resp.unwrap().to_string(), "hi");
102 }
103
104 #[test]
105 fn test_traits() {
106 assert_eq!(AppError::new("hi").message, "hi");
107 assert_eq!(AppError::new("hi".to_string()).message, "hi");
108 }
109
110 #[test]
111 fn test_code() {
112 let r: Result<(), String> = Err("hi".to_string());
113 let mapped = r.map_err(AppError::code(StatusCode::METHOD_NOT_ALLOWED));
114
115 assert!(mapped.is_err());
116
117 let e = mapped.unwrap_err();
118
119 assert_eq!(e.code, StatusCode::METHOD_NOT_ALLOWED);
120 assert_eq!(e.message, "hi");
121 }
122}