1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum HttpError {
8 #[error("HTTP error ({status}): {message}")]
10 Status {
11 status: u16,
13 message: String,
15 },
16 #[error("Connection error: {0}")]
18 Connection(String),
19 #[error("Request timeout")]
21 Timeout,
22 #[error("Serialization error: {0}")]
24 Serialization(String),
25 #[error("Proxy error: {0}")]
27 Proxy(String),
28 #[error("Client build error: {0}")]
30 Build(String),
31 #[error("{0}")]
33 Other(String),
34}
35
36impl From<reqwest::Error> for HttpError {
37 fn from(err: reqwest::Error) -> Self {
38 if err.is_timeout() {
39 HttpError::Timeout
40 } else if err.is_builder() {
41 HttpError::Build(err.to_string())
42 } else if let Some(status) = err.status() {
43 HttpError::Status {
44 status: status.as_u16(),
45 message: err.to_string(),
46 }
47 } else {
48 #[cfg(not(target_arch = "wasm32"))]
50 if err.is_connect() {
51 return HttpError::Connection(err.to_string());
52 }
53 HttpError::Other(err.to_string())
54 }
55 }
56}
57
58impl From<serde_json::Error> for HttpError {
59 fn from(err: serde_json::Error) -> Self {
60 HttpError::Serialization(err.to_string())
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67
68 #[test]
69 fn test_http_error_status_display() {
70 let error = HttpError::Status {
71 status: 404,
72 message: "Not Found".to_string(),
73 };
74 assert_eq!(format!("{}", error), "HTTP error (404): Not Found");
75 }
76
77 #[test]
78 fn test_http_error_connection_display() {
79 let error = HttpError::Connection("connection refused".to_string());
80 assert_eq!(format!("{}", error), "Connection error: connection refused");
81 }
82
83 #[test]
84 fn test_http_error_timeout_display() {
85 let error = HttpError::Timeout;
86 assert_eq!(format!("{}", error), "Request timeout");
87 }
88
89 #[test]
90 fn test_http_error_serialization_display() {
91 let error = HttpError::Serialization("invalid JSON".to_string());
92 assert_eq!(format!("{}", error), "Serialization error: invalid JSON");
93 }
94
95 #[test]
96 fn test_http_error_proxy_display() {
97 let error = HttpError::Proxy("proxy unreachable".to_string());
98 assert_eq!(format!("{}", error), "Proxy error: proxy unreachable");
99 }
100
101 #[test]
102 fn test_http_error_build_display() {
103 let error = HttpError::Build("invalid config".to_string());
104 assert_eq!(format!("{}", error), "Client build error: invalid config");
105 }
106
107 #[test]
108 fn test_http_error_other_display() {
109 let error = HttpError::Other("unknown error".to_string());
110 assert_eq!(format!("{}", error), "unknown error");
111 }
112
113 #[test]
114 fn test_from_serde_json_error() {
115 let result: Result<String, _> = serde_json::from_str("not valid json");
117 let json_error = result.expect_err("Invalid JSON should produce an error");
118 let http_error: HttpError = json_error.into();
119
120 match http_error {
121 HttpError::Serialization(msg) => {
122 assert!(
123 msg.contains("expected"),
124 "Error message should describe JSON error"
125 );
126 }
127 _ => panic!("Expected HttpError::Serialization"),
128 }
129 }
130}