1#[derive(thiserror::Error, Debug)]
5pub enum HttpError {
6
7 #[error("Reqwest failure: {0}")]
9 RequestError(#[from] reqwest::Error),
10
11 #[error("Invalid URL: {0}")]
13 UrlParseError(#[from] url::ParseError),
14
15 #[error("JSON parsing failed: {0}")]
17 JsonError(#[from] serde_json::Error),
18
19 #[error("IO error: {0}")]
21 IOError(#[from] std::io::Error),
22
23 #[error("{}", HttpError::format_http_error(.status, &.message))]
25 HttpStatus {
26 status: u16,
28 message: String
30 },
31
32 #[error("API responded with success=false: {message}")]
34 ApiError {
35 message: String
37 },
38
39 #[error("TLS error: {0}")]
41 TLSError(String),
42
43 #[error("Missing 'response' field in API response")]
45 MissingResponseField,
46
47 #[error("Missing 'type' field in API response")]
49 MissingTypeField,
50
51 #[error("Missing 'data' field in API response")]
53 MissingDataField,
54
55 #[error("Type mismatch: expected '{expected}', got '{actual}'")]
57 ResponseTypeMismatch {
58 expected: String,
60 actual: String
62 }
63}
64impl HttpError {
65 fn status_text(status: u16) -> &'static str {
66 match status {
67 200 => "OK",
68 400 => "Bad Request",
69 401 => "Unauthorized",
70 403 => "Forbidden",
71 404 => "Not Found",
72 405 => "Method Not Allowed",
73 408 => "Not Acceptable",
74 429 => "Too Many Requests",
75 500 => "Internal Server Error",
76 503 => "Service Unavailable",
77 504 => "Gateway Timeout",
78 _ => "Unknown"
79 }
80 }
81
82 fn format_http_error(status: &u16, message: &str) -> String {
83 if message.trim().is_empty() {
84 format!("HTTP {status} {}", Self::status_text(*status))
85 } else {
86 format!("HTTP {status}: {}", message)
87 }
88 }
89}
90
91pub type HttpResult<T> = Result<T, HttpError>;