rusty_bybit/
error.rs

1//! Error types for Bybit API
2//!
3//! Comprehensive error handling for SDK operations.
4//!
5//! # Example
6//!
7//! ```rust,no_run
8//! use rusty_bybit::{BybitError, BybitClient};
9//!
10//! #[tokio::main]
11//! async fn main() {
12//!     let client = BybitClient::testnet();
13//!
14//!     match client.get_server_time().await {
15//!         Ok(time) => println!("Server time: {}", time.time_second),
16//!         Err(BybitError::ApiError { ret_code, ret_msg }) => {
17//!             if ret_code == 10006 {
18//!                 eprintln!("Rate limit exceeded: {}", ret_msg);
19//!             } else if ret_code == 110004 {
20//!                 eprintln!("Insufficient balance: {}", ret_msg);
21//!             } else {
22//!                 eprintln!("API error {}: {}", ret_code, ret_msg);
23//!             }
24//!         }
25//!         Err(e) => eprintln!("Error: {}", e),
26//!     }
27//! }
28//! ```
29
30#[derive(Debug, thiserror::Error)]
31pub enum BybitError {
32    RequestError(#[from] reqwest::Error),
33
34    ApiError {
35        ret_code: i32,
36        ret_msg: String,
37    },
38
39    InvalidTimestamp(String),
40
41    SerializationError(#[from] serde_json::Error),
42
43    InvalidParameter(String),
44
45    AuthenticationError(String),
46
47    RateLimitExceeded {
48        limit_type: String,
49        limit_reset_ms: Option<u64>,
50    },
51
52    InvalidEnumValue {
53        enum_name: String,
54        value: String,
55    },
56
57    MissingRequiredField {
58        field_name: String,
59    },
60}
61
62impl std::fmt::Display for BybitError {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        match self {
65            BybitError::RequestError(e) => write!(f, "HTTP request failed: {}", e),
66            BybitError::ApiError { ret_code, ret_msg } => {
67                write!(f, "API error (code {}): {}", ret_code, ret_msg)
68            }
69            BybitError::InvalidTimestamp(msg) => {
70                write!(f, "Invalid timestamp: {}", msg)
71            }
72            BybitError::SerializationError(e) => {
73                write!(f, "Serialization error: {}", e)
74            }
75            BybitError::InvalidParameter(msg) => {
76                write!(f, "Invalid parameter: {}", msg)
77            }
78            BybitError::AuthenticationError(msg) => {
79                write!(f, "Authentication failed: {}", msg)
80            }
81            BybitError::RateLimitExceeded { limit_type, .. } => {
82                write!(f, "Rate limit exceeded: {}", limit_type)
83            }
84            BybitError::InvalidEnumValue { enum_name, value } => {
85                write!(f, "Invalid enum value for {}: {}", enum_name, value)
86            }
87            BybitError::MissingRequiredField { field_name } => {
88                write!(f, "Missing required field: {}", field_name)
89            }
90        }
91    }
92}
93
94pub type Result<T> = std::result::Result<T, BybitError>;
95
96#[cfg(test)]
97mod tests {
98    use super::*;
99
100    #[test]
101    fn test_bybit_error_display_api_error() {
102        let error = BybitError::ApiError {
103            ret_code: 10001,
104            ret_msg: "Invalid request".to_string(),
105        };
106
107        let display = format!("{}", error);
108        assert!(display.contains("API error"));
109        assert!(display.contains("10001"));
110        assert!(display.contains("Invalid request"));
111    }
112
113    #[test]
114    fn test_bybit_error_display_invalid_timestamp() {
115        let error = BybitError::InvalidTimestamp("Timestamp expired".to_string());
116
117        let display = format!("{}", error);
118        assert!(display.contains("Invalid timestamp"));
119        assert!(display.contains("Timestamp expired"));
120    }
121
122    #[test]
123    fn test_bybit_error_display_serialization_error() {
124        let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
125        let error = BybitError::SerializationError(json_error);
126
127        let display = format!("{}", error);
128        assert!(display.contains("Serialization error"));
129    }
130
131    #[test]
132    fn test_bybit_error_display_invalid_parameter() {
133        let error = BybitError::InvalidParameter("Invalid symbol".to_string());
134
135        let display = format!("{}", error);
136        assert!(display.contains("Invalid parameter"));
137        assert!(display.contains("Invalid symbol"));
138    }
139
140    #[test]
141    fn test_bybit_error_display_authentication_error() {
142        let error = BybitError::AuthenticationError("Invalid signature".to_string());
143
144        let display = format!("{}", error);
145        assert!(display.contains("Authentication failed"));
146        assert!(display.contains("Invalid signature"));
147    }
148
149    #[test]
150    fn test_bybit_error_display_rate_limit_exceeded() {
151        let error = BybitError::RateLimitExceeded {
152            limit_type: "API".to_string(),
153            limit_reset_ms: Some(5000),
154        };
155
156        let display = format!("{}", error);
157        assert!(display.contains("Rate limit exceeded"));
158        assert!(display.contains("API"));
159    }
160
161    #[test]
162    fn test_bybit_error_display_invalid_enum_value() {
163        let error = BybitError::InvalidEnumValue {
164            enum_name: "Side".to_string(),
165            value: "InvalidSide".to_string(),
166        };
167
168        let display = format!("{}", error);
169        assert!(display.contains("Invalid enum value"));
170        assert!(display.contains("Side"));
171        assert!(display.contains("InvalidSide"));
172    }
173
174    #[test]
175    fn test_bybit_error_display_missing_required_field() {
176        let error = BybitError::MissingRequiredField {
177            field_name: "symbol".to_string(),
178        };
179
180        let display = format!("{}", error);
181        assert!(display.contains("Missing required field"));
182        assert!(display.contains("symbol"));
183    }
184
185    #[test]
186    fn test_bybit_error_debug() {
187        let error = BybitError::ApiError {
188            ret_code: 10006,
189            ret_msg: "Rate limit exceeded".to_string(),
190        };
191
192        let debug = format!("{:?}", error);
193        assert!(debug.contains("ApiError"));
194    }
195}