sms_client/http/
error.rs

1//! HTTP interface related errors.
2
3/// An error originating from the SMS HttpClient.
4#[derive(thiserror::Error, Debug)]
5pub enum HttpError {
6
7    /// Network request failed (connection issues, timeouts, etc.)
8    #[error("Reqwest failure: {0}")]
9    RequestError(#[from] reqwest::Error),
10
11    /// Failed to parse the provided URL.
12    #[error("Invalid URL: {0}")]
13    UrlParseError(#[from] url::ParseError),
14
15    /// Failed to parse JSON response from the API.
16    #[error("JSON parsing failed: {0}")]
17    JsonError(#[from] serde_json::Error),
18
19    /// System IO error
20    #[error("IO error: {0}")]
21    IOError(#[from] std::io::Error),
22
23    /// HTTP request returned a non-success status code.
24    #[error("{}", HttpError::format_http_error(.status, &.message))]
25    HttpStatus {
26        /// HTTP status returned in response.
27        status: u16,
28        /// Full response body as text.
29        message: String
30    },
31
32    /// API returned success=false with an error message.
33    #[error("API responded with success=false: {message}")]
34    ApiError {
35        /// The error_message key from response.
36        message: String
37    },
38
39    /// TLS configuration error
40    #[error("TLS error: {0}")]
41    TLSError(String),
42
43    /// API response missing the expected 'response' field.
44    #[error("Missing 'response' field in API response")]
45    MissingResponseField,
46
47    /// Modem response missing the expected 'type' field.
48    #[error("Missing 'type' field in API response")]
49    MissingTypeField,
50
51    /// Modem response missing the expected 'data' field.
52    #[error("Missing 'data' field in API response")]
53    MissingDataField,
54
55    /// Modem response type doesn't match what was expected.
56    #[error("Type mismatch: expected '{expected}', got '{actual}'")]
57    ResponseTypeMismatch {
58        /// The expected response data-type.
59        expected: String,
60        /// The actual response data-type.
61        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
91/// Result type alias for HTTP operations.
92pub type HttpResult<T> = Result<T, HttpError>;