Skip to main content

redis_enterprise/
error.rs

1//! Error types for REST API operations
2
3use std::time::Duration;
4use thiserror::Error;
5
6#[derive(Error, Debug, Clone)]
7pub enum RestError {
8    #[error("Invalid URL: {0}")]
9    InvalidUrl(String),
10
11    #[error("HTTP request failed: {0}")]
12    RequestFailed(String),
13
14    #[error("Authentication failed")]
15    AuthenticationFailed,
16
17    #[error("API error: {message} (code: {code})")]
18    ApiError { code: u16, message: String },
19
20    #[error("Serialization error: {0}")]
21    SerializationError(String),
22
23    #[error("Parse error: {0}")]
24    ParseError(String),
25
26    #[error("Connection error: {0}")]
27    ConnectionError(String),
28
29    #[error("TLS certificate error: {0}")]
30    TlsError(String),
31
32    #[error("Not connected to REST API")]
33    NotConnected,
34
35    #[error("Validation error: {0}")]
36    ValidationError(String),
37
38    #[error("Resource not found")]
39    NotFound,
40
41    #[error("Unauthorized")]
42    Unauthorized,
43
44    #[error("Server error: {0}")]
45    ServerError(String),
46
47    #[error("Request timed out")]
48    Timeout,
49
50    #[error("Rate limited{}", .retry_after.map(|d| format!(" (retry after {:?})", d)).unwrap_or_default())]
51    RateLimited { retry_after: Option<Duration> },
52
53    #[error("Resource already exists")]
54    AlreadyExists,
55
56    #[error("Conflict: {0}")]
57    Conflict(String),
58
59    #[error("Cluster is busy or unavailable")]
60    ClusterBusy,
61}
62
63impl From<reqwest::Error> for RestError {
64    fn from(err: reqwest::Error) -> Self {
65        RestError::RequestFailed(err.to_string())
66    }
67}
68
69impl From<serde_json::Error> for RestError {
70    fn from(err: serde_json::Error) -> Self {
71        RestError::SerializationError(err.to_string())
72    }
73}
74
75impl RestError {
76    /// Check if this is a not found error
77    pub fn is_not_found(&self) -> bool {
78        matches!(self, RestError::NotFound)
79            || matches!(self, RestError::ApiError { code, .. } if *code == 404)
80    }
81
82    /// Check if this is an authentication error
83    pub fn is_unauthorized(&self) -> bool {
84        matches!(self, RestError::Unauthorized)
85            || matches!(self, RestError::AuthenticationFailed)
86            || matches!(self, RestError::ApiError { code, .. } if *code == 401)
87    }
88
89    /// Check if this is a server error
90    pub fn is_server_error(&self) -> bool {
91        matches!(self, RestError::ServerError(_))
92            || matches!(self, RestError::ApiError { code, .. } if *code >= 500)
93    }
94
95    /// Check if this is a timeout error
96    pub fn is_timeout(&self) -> bool {
97        matches!(self, RestError::Timeout)
98    }
99
100    /// Check if this is a rate limit error
101    pub fn is_rate_limited(&self) -> bool {
102        matches!(self, RestError::RateLimited { .. })
103            || matches!(self, RestError::ApiError { code, .. } if *code == 429)
104    }
105
106    /// Check if this is a conflict/already exists error
107    pub fn is_conflict(&self) -> bool {
108        matches!(self, RestError::AlreadyExists)
109            || matches!(self, RestError::Conflict(_))
110            || matches!(self, RestError::ApiError { code, .. } if *code == 409)
111    }
112
113    /// Check if this is a cluster busy error
114    pub fn is_cluster_busy(&self) -> bool {
115        matches!(self, RestError::ClusterBusy)
116            || matches!(self, RestError::ApiError { code, .. } if *code == 503)
117    }
118
119    /// Check if this error is retryable
120    pub fn is_retryable(&self) -> bool {
121        self.is_timeout()
122            || self.is_rate_limited()
123            || self.is_cluster_busy()
124            || self.is_server_error()
125    }
126
127    /// Check if this is a bad request / validation error
128    pub fn is_bad_request(&self) -> bool {
129        matches!(self, RestError::ValidationError(_))
130            || matches!(self, RestError::ApiError { code, .. } if *code == 400)
131    }
132}
133
134pub type Result<T> = std::result::Result<T, RestError>;