1#[derive(thiserror::Error, Debug)]
5pub enum HttpError {
6
7 #[error("Network request failed: {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("{}", HttpError::format_http_error(.status, &.message))]
21 HttpStatus {
22 status: u16,
24 message: String
26 },
27
28 #[error("API responded with success=false: {message}")]
30 ApiError {
31 message: String
33 },
34
35 #[error("Missing 'response' field in API response")]
37 MissingResponseField,
38
39 #[error("Missing 'type' field in API response")]
41 MissingTypeField,
42
43 #[error("Missing 'data' field in API response")]
45 MissingDataField,
46
47 #[error("Type mismatch: expected '{expected}', got '{actual}'")]
49 ResponseTypeMismatch {
50 expected: String,
52 actual: String
54 }
55}
56impl HttpError {
57 fn status_text(status: u16) -> &'static str {
58 match status {
59 200 => "OK",
60 400 => "Bad Request",
61 401 => "Unauthorized",
62 403 => "Forbidden",
63 404 => "Not Found",
64 405 => "Method Not Allowed",
65 408 => "Not Acceptable",
66 429 => "Too Many Requests",
67 500 => "Internal Server Error",
68 503 => "Service Unavailable",
69 504 => "Gateway Timeout",
70 _ => "Unknown"
71 }
72 }
73
74 fn format_http_error(status: &u16, message: &str) -> String {
75 if message.trim().is_empty() {
76 format!("HTTP {status} {}", Self::status_text(*status))
77 } else {
78 format!("HTTP {status}: {}", message)
79 }
80 }
81}
82
83pub type HttpResult<T> = Result<T, HttpError>;