redis_cloud/error.rs
1//! Error types for Redis Cloud API client
2//!
3//! This module provides error handling for all API operations, including
4//! typed errors for common HTTP status codes and network failures.
5//!
6//! # Error Types
7//!
8//! - `CloudError::BadRequest` - HTTP 400 errors
9//! - `CloudError::AuthenticationFailed` - HTTP 401 errors
10//! - `CloudError::Forbidden` - HTTP 403 errors
11//! - `CloudError::NotFound` - HTTP 404 errors
12//! - `CloudError::RateLimited` - HTTP 429 errors
13//! - `CloudError::InternalServerError` - HTTP 500 errors
14//! - `CloudError::ServiceUnavailable` - HTTP 503 errors
15//!
16//! # Retryable Errors
17//!
18//! Some errors are considered retryable (transient failures that may succeed on retry):
19//! - Rate limited (429)
20//! - Service unavailable (503)
21//! - Connection/request errors (network issues)
22//!
23//! Use `CloudError::is_retryable()` to check if an error should be retried.
24
25use thiserror::Error;
26
27/// Errors that can occur when interacting with the Redis Cloud API
28#[derive(Error, Debug, Clone)]
29pub enum CloudError {
30 /// HTTP request failed (network error, timeout, etc.)
31 #[error("HTTP request failed: {0}")]
32 Request(String),
33
34 /// Bad Request (400) - Invalid request parameters
35 #[error("Bad Request (400): {message}")]
36 BadRequest {
37 /// Error message from the API
38 message: String,
39 },
40
41 /// Authentication failed (401) - Invalid or missing credentials
42 #[error("Authentication failed (401): {message}")]
43 AuthenticationFailed {
44 /// Error message from the API
45 message: String,
46 },
47
48 /// Forbidden (403) - Insufficient permissions
49 #[error("Forbidden (403): {message}")]
50 Forbidden {
51 /// Error message from the API
52 message: String,
53 },
54
55 /// Not Found (404) - Resource does not exist
56 #[error("Not Found (404): {message}")]
57 NotFound {
58 /// Error message from the API
59 message: String,
60 },
61
62 /// Precondition Failed (412) - Feature flag is disabled
63 #[error("Precondition Failed (412): Feature flag for this flow is off")]
64 PreconditionFailed,
65
66 /// Rate Limited (429) - Too many requests
67 #[error("Rate Limited (429): {message}")]
68 RateLimited {
69 /// Error message from the API
70 message: String,
71 },
72
73 /// Internal Server Error (500) - Server-side error
74 #[error("Internal Server Error (500): {message}")]
75 InternalServerError {
76 /// Error message from the API
77 message: String,
78 },
79
80 /// Service Unavailable (503) - Server temporarily unavailable
81 #[error("Service Unavailable (503): {message}")]
82 ServiceUnavailable {
83 /// Error message from the API
84 message: String,
85 },
86
87 /// Generic API error for other HTTP status codes
88 #[error("API error ({code}): {message}")]
89 ApiError {
90 /// HTTP status code
91 code: u16,
92 /// Error message from the API
93 message: String,
94 },
95
96 /// Connection error (failed to establish connection)
97 #[error("Connection error: {0}")]
98 ConnectionError(String),
99
100 /// JSON serialization/deserialization error
101 #[error("JSON error: {0}")]
102 JsonError(String),
103}
104
105impl CloudError {
106 /// Returns true if this error is retryable.
107 ///
108 /// Retryable errors include:
109 /// - Rate limited (429)
110 /// - Service unavailable (503)
111 /// - Connection/request errors (may be transient network issues)
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use redis_cloud::CloudError;
117 ///
118 /// let error = CloudError::RateLimited { message: "Too many requests".to_string() };
119 /// assert!(error.is_retryable());
120 ///
121 /// let error = CloudError::NotFound { message: "Resource not found".to_string() };
122 /// assert!(!error.is_retryable());
123 /// ```
124 #[must_use]
125 pub fn is_retryable(&self) -> bool {
126 matches!(
127 self,
128 CloudError::RateLimited { .. }
129 | CloudError::ServiceUnavailable { .. }
130 | CloudError::Request(_)
131 | CloudError::ConnectionError(_)
132 )
133 }
134}
135
136impl From<reqwest::Error> for CloudError {
137 fn from(err: reqwest::Error) -> Self {
138 CloudError::Request(err.to_string())
139 }
140}
141
142impl From<serde_json::Error> for CloudError {
143 fn from(err: serde_json::Error) -> Self {
144 CloudError::JsonError(err.to_string())
145 }
146}
147
148/// Result type alias for Redis Cloud operations
149pub type Result<T> = std::result::Result<T, CloudError>;