Skip to main content

coinbase_advanced/
error.rs

1use std::time::Duration;
2
3/// Result type alias for coinbase-client operations.
4pub type Result<T> = std::result::Result<T, Error>;
5
6/// Error types for the Coinbase client.
7#[derive(Debug, thiserror::Error)]
8pub enum Error {
9    /// Configuration error (missing credentials, invalid format, etc.)
10    #[error("Configuration error: {0}")]
11    Config(String),
12
13    /// JWT signing error
14    #[error("JWT error: {0}")]
15    Jwt(String),
16
17    /// HTTP transport error
18    #[error("HTTP error: {0}")]
19    Http(#[from] reqwest::Error),
20
21    /// Request building error
22    #[error("Request error: {0}")]
23    Request(String),
24
25    /// API error response from Coinbase
26    #[error("API error: {message}")]
27    Api {
28        /// Error message from the API
29        message: String,
30        /// HTTP status code
31        status: u16,
32        /// Raw error response body
33        body: Option<String>,
34    },
35
36    /// Rate limit exceeded
37    #[error("Rate limited, retry after {retry_after:?}")]
38    RateLimited {
39        /// Duration to wait before retrying
40        retry_after: Option<Duration>,
41    },
42
43    /// Response parsing error
44    #[error("Parse error: {message}")]
45    Parse {
46        /// Description of the parse error
47        message: String,
48        /// Raw response body that failed to parse
49        body: Option<String>,
50    },
51
52    /// Authentication error
53    #[error("Authentication error: {0}")]
54    Auth(String),
55
56    /// URL construction error
57    #[error("URL error: {0}")]
58    Url(#[from] url::ParseError),
59
60    /// WebSocket error
61    #[error("WebSocket error: {0}")]
62    WebSocket(String),
63}
64
65impl Error {
66    /// Create a new configuration error.
67    pub fn config(msg: impl Into<String>) -> Self {
68        Self::Config(msg.into())
69    }
70
71    /// Create a new JWT error.
72    pub fn jwt(msg: impl Into<String>) -> Self {
73        Self::Jwt(msg.into())
74    }
75
76    /// Create a new request error.
77    pub fn request(msg: impl Into<String>) -> Self {
78        Self::Request(msg.into())
79    }
80
81    /// Create a new API error.
82    pub fn api(status: u16, message: impl Into<String>, body: Option<String>) -> Self {
83        Self::Api {
84            message: message.into(),
85            status,
86            body,
87        }
88    }
89
90    /// Create a new parse error.
91    pub fn parse(message: impl Into<String>, body: Option<String>) -> Self {
92        Self::Parse {
93            message: message.into(),
94            body,
95        }
96    }
97
98    /// Create a new authentication error.
99    pub fn auth(msg: impl Into<String>) -> Self {
100        Self::Auth(msg.into())
101    }
102
103    /// Create a new WebSocket error.
104    pub fn websocket(msg: impl Into<String>) -> Self {
105        Self::WebSocket(msg.into())
106    }
107
108    /// Check if this error is a rate limit error.
109    pub fn is_rate_limited(&self) -> bool {
110        matches!(self, Self::RateLimited { .. })
111    }
112
113    /// Check if this error is retryable.
114    pub fn is_retryable(&self) -> bool {
115        match self {
116            Self::RateLimited { .. } => true,
117            Self::Http(e) => e.is_timeout() || e.is_connect(),
118            Self::Api { status, .. } => *status >= 500,
119            _ => false,
120        }
121    }
122}