scratch_server/errors/
api_error.rs1use 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}