1use crate::{Response, ui::{div, h1, p, text, get_renderer}};
2use hyper::StatusCode;
3use std::fmt;
4use std::error::Error as StdError; #[derive(Debug, Clone)] pub enum AppError {
8 NotFound(String),
9 Internal(String),
10 BadRequest(String),
11 Unauthorized(String),
12 Forbidden(String),
13 #[allow(dead_code)] Custom(StatusCode, String),
16}
17
18impl fmt::Display for AppError {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 match self {
21 AppError::NotFound(msg) => write!(f, "Not Found: {}", msg),
22 AppError::Internal(msg) => write!(f, "Internal Server Error: {}", msg),
23 AppError::BadRequest(msg) => write!(f, "Bad Request: {}", msg),
24 AppError::Unauthorized(msg) => write!(f, "Unauthorized: {}", msg),
25 AppError::Forbidden(msg) => write!(f, "Forbidden: {}", msg),
26 AppError::Custom(_, msg) => write!(f, "Custom Error: {}", msg),
27 }
28 }
29}
30
31impl StdError for AppError {}
32
33impl From<Box<dyn StdError + Send + Sync>> for AppError {
35 fn from(err: Box<dyn StdError + Send + Sync>) -> Self {
36 if let Some(app_err) = err.downcast_ref::<AppError>() {
39 app_err.clone() } else {
41 AppError::Internal(err.to_string())
42 }
43 }
44}
45
46impl From<hyper::Error> for AppError {
47 fn from(err: hyper::Error) -> Self {
48 AppError::Internal(format!("Hyper error: {}", err))
49 }
50}
51
52impl From<serde_json::Error> for AppError {
53 fn from(err: serde_json::Error) -> Self {
54 AppError::BadRequest(format!("JSON parsing error: {}", err))
55 }
56}
57
58impl From<std::io::Error> for AppError {
59 fn from(err: std::io::Error) -> Self {
60 AppError::Internal(format!("IO error: {}", err))
61 }
62}
63
64impl From<multer::Error> for AppError {
65 fn from(err: multer::Error) -> Self {
66 AppError::BadRequest(format!("Multipart parsing error: {}", err))
67 }
68}
69
70impl From<url::ParseError> for AppError {
71 fn from(err: url::ParseError) -> Self {
72 AppError::BadRequest(format!("URL parsing error: {}", err))
73 }
74}
75
76pub trait IntoResponse {
78 fn into_response(&self) -> Result<Response, Box<dyn StdError + Send + Sync>>;
79}
80
81impl IntoResponse for AppError {
82 fn into_response(&self) -> Result<Response, Box<dyn StdError + Send + Sync>> {
83 let (status, message) = match self {
84 AppError::NotFound(msg) => (StatusCode::NOT_FOUND, msg.clone()),
85 AppError::Internal(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg.clone()),
86 AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg.clone()),
87 AppError::Unauthorized(msg) => (StatusCode::UNAUTHORIZED, msg.clone()),
88 AppError::Forbidden(msg) => (StatusCode::FORBIDDEN, msg.clone()),
89 AppError::Custom(s, msg) => (*s, msg.clone()),
90 };
91
92 let error_page = div()
93 .class("container")
94 .child(h1().child(text(&format!("Error {}: {}", status.as_u16(), status.canonical_reason().unwrap_or("Unknown Error")))))
95 .child(p().child(text(&message)));
96
97 get_renderer().render_to_response(&error_page)
98 .map(|res| res.status(status))
99 .map_err(|e| e) }
101}