scratch_server/errors/
api_error.rs

1use std::fmt;
2
3use crate::{http_parse_error::HttpParseError, Body, HttpResponse};
4
5#[derive(Debug)]
6pub struct ApiError {
7    pub error_response: HttpResponse,
8    pub method: Option<String>,
9    pub path: Option<String>,
10}
11
12impl ApiError {
13    pub fn new_with_html(code: u16, message: &str) -> Self {
14        ApiError {
15            error_response: format_error(code, message),
16            method: None,
17            path: None,
18        }
19    }
20
21    pub fn new_with_json(code: u16, message: &str) -> Self {
22        ApiError {
23            error_response: HttpResponse::new(
24                Some(Body::Json(serde_json::json!({"message": message}))),
25                None,
26                code,
27            ),
28            method: None,
29            path: None,
30        }
31    }
32
33    pub fn new_with_custom(response: HttpResponse) -> Self {
34        ApiError {
35            error_response: response,
36            method: None,
37            path: None,
38        }
39    }
40}
41
42impl fmt::Display for ApiError {
43    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44        write!(f, "{:?}", self)
45    }
46}
47
48impl std::error::Error for ApiError {}
49
50impl From<std::io::Error> for ApiError {
51    fn from(error: std::io::Error) -> Self {
52        ApiError::new_with_html(500, &format!("IO Error: {}", error))
53    }
54}
55
56impl From<Box<dyn std::error::Error>> for ApiError {
57    fn from(error: Box<dyn std::error::Error>) -> ApiError {
58        ApiError::new_with_json(500, &error.to_string())
59    }
60}
61
62impl From<serde_json::Error> for ApiError {
63    fn from(error: serde_json::Error) -> Self {
64        ApiError::new_with_json(400, &format!("JSON Serialization Error: {}", error))
65    }
66}
67
68impl From<&str> for ApiError {
69    fn from(error: &str) -> Self {
70        ApiError::new_with_json(400, error)
71    }
72}
73
74impl From<HttpParseError> for ApiError {
75    fn from(error: HttpParseError) -> Self {
76        ApiError::new_with_json(
77            400,
78            &format!("Error parsing HTTP request: {}", error.message),
79        )
80    }
81}
82
83fn format_error(error_code: u16, message: &str) -> HttpResponse {
84    let html = format!(
85        "<!DOCTYPE html>
86    <html lang=\"en\">
87    <head>
88        <meta charset=\"UTF-8\">
89        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
90        <title>Error</title>
91        <style>
92        body {{
93            display: flex;
94            justify-content: center;
95            align-items: center;
96            height: 100vh;
97            font-family: Arial, sans-serif;
98        }}
99        .error-container {{
100            text-align: center;
101        }}
102        .error-container h1 {{
103            font-size: 3em;
104            color: #ff0000;
105        }}
106        .error-container p {{
107            font-size: 1.5em;
108        }}
109    </style>
110    </head>
111
112    <body>
113        <div class=\"error-container\">
114            <h1>{} {}</h1>
115            <p>{}</p>
116        </div>
117    </body>
118    </html>",
119        error_code,
120        get_cannonical_reason(error_code),
121        message
122    );
123    HttpResponse::new(
124        Some(Body::Text(html)),
125        Some(String::from("text/html")),
126        error_code,
127    )
128}
129
130fn get_cannonical_reason<'a>(status_code: u16) -> &'a str {
131    match status_code {
132        200 => "OK",
133        201 => "Created",
134        204 => "No Content",
135        301 => "Moved Permanently",
136        302 => "Found",
137        304 => "Not Modified",
138        400 => "Bad Request",
139        401 => "Unauthorized",
140        403 => "Forbidden",
141        404 => "Not Found",
142        405 => "Method Not Allowed",
143        500 => "Internal Server Error",
144        501 => "Not Implemented",
145        502 => "Bad Gateway",
146        503 => "Service Unavailable",
147        _ => "Unknown Status Code",
148    }
149}