Skip to main content

rust_okx/
error.rs

1//! Error types returned by the crate.
2
3use crate::transport::TransportError;
4
5/// A boxed, thread-safe error used as the `source` of opaque variants so that
6/// concrete dependency error types (e.g. `serde_json::Error`) do not leak into
7/// this crate's public API.
8type BoxError = Box<dyn std::error::Error + Send + Sync>;
9
10/// Errors that can occur while making an OKX API request.
11///
12/// The enum is [`#[non_exhaustive]`](https://doc.rust-lang.org/reference/attributes/type_system.html)
13/// so new variants can be added without a breaking change. Downstream code can
14/// match on [`Error::Api`] and inspect the OKX error `code` (kept as a `String`,
15/// since OKX codes are not guaranteed to be parseable integers).
16#[derive(Debug, thiserror::Error)]
17#[non_exhaustive]
18pub enum Error {
19    /// The underlying HTTP transport failed (connection, TLS, timeout, …).
20    #[error("transport error: {0}")]
21    Transport(#[from] TransportError),
22
23    /// The request could not be encoded (query string or JSON body).
24    #[error("failed to encode request: {0}")]
25    Encode(#[source] BoxError),
26
27    /// The response body could not be decoded into the expected model.
28    #[error("failed to decode response: {0}")]
29    Decode(#[source] BoxError),
30
31    /// OKX returned a non-zero response code.
32    #[error("OKX API error {code}: {message}")]
33    Api {
34        /// OKX error code (e.g. `"50011"`). Kept as a string deliberately.
35        code: String,
36        /// Human-readable error message from OKX.
37        message: String,
38    },
39
40    /// The HTTP response had a non-success status before the OKX response
41    /// envelope could be decoded.
42    #[error("HTTP status {status}: {body}")]
43    HttpStatus {
44        /// HTTP response status code.
45        status: http::StatusCode,
46        /// Response body, decoded lossily as UTF-8 for diagnostics.
47        body: String,
48    },
49
50    /// The client was used in an invalid way (e.g. an authenticated endpoint
51    /// was called without credentials).
52    #[error("invalid configuration: {0}")]
53    Configuration(String),
54}
55
56impl Error {
57    /// Construct an [`Error::Encode`] from any boxable error.
58    pub(crate) fn encode(err: impl Into<BoxError>) -> Self {
59        Error::Encode(err.into())
60    }
61
62    /// Construct an [`Error::Decode`] from any boxable error.
63    pub(crate) fn decode(err: impl Into<BoxError>) -> Self {
64        Error::Decode(err.into())
65    }
66}