Skip to main content

databento/
error.rs

1//! Types for errors received from the API and occurring in the clients.
2use thiserror::Error;
3
4/// An error that can occur while working with Databento's API.
5#[derive(Debug, Error)]
6#[non_exhaustive]
7pub enum Error {
8    /// An invalid argument was passed to a function.
9    #[error("bad argument `{param_name}`: {desc}")]
10    BadArgument {
11        /// The name of the parameter to which the bad argument was passed.
12        param_name: &'static str,
13        /// The description of why the argument was invalid.
14        desc: String,
15    },
16    /// An I/O error while reading or writing DBN or another encoding.
17    #[error("I/O error: {0:?}")]
18    Io(#[from] std::io::Error),
19    /// An HTTP error.
20    #[cfg(feature = "historical")]
21    #[error("HTTP error: {0:?}")]
22    Http(#[from] reqwest::Error),
23    /// An error related to JSON decoding.
24    #[cfg(feature = "historical")]
25    #[error("JSON error: {0:?}")]
26    Json(#[from] serde_json::Error),
27    /// An error related to JSON decoding.
28    #[cfg(feature = "historical")]
29    #[error("invalid UTF-8: {0:?}")]
30    Utf8(#[from] std::str::Utf8Error),
31    /// An error from the Databento API.
32    #[cfg(feature = "historical")]
33    #[error("API error: {0}")]
34    Api(ApiError),
35    /// An error internal to the client.
36    #[error("internal error: {0}")]
37    Internal(String),
38    /// An error related to DBN encoding or decoding.
39    #[error("DBN error: {0}")]
40    Dbn(#[source] dbn::Error),
41    /// An when authentication failed.
42    #[error("authentication failed: {0}")]
43    Auth(String),
44}
45/// An alias for a `Result` with [`databento::Error`](crate::Error) as the error type.
46pub type Result<T> = std::result::Result<T, Error>;
47
48/// An error from the Databento API.
49#[cfg(feature = "historical")]
50#[derive(Debug)]
51pub struct ApiError {
52    /// The request ID.
53    pub request_id: Option<String>,
54    /// The HTTP status code of the response.
55    pub status_code: reqwest::StatusCode,
56    /// The message from the Databento API.
57    pub message: String,
58    /// The link to documentation related to the error.
59    pub docs_url: Option<String>,
60}
61
62impl Error {
63    pub(crate) fn bad_arg(param_name: &'static str, desc: impl ToString) -> Self {
64        Self::BadArgument {
65            param_name,
66            desc: desc.to_string(),
67        }
68    }
69
70    pub(crate) fn internal(msg: impl ToString) -> Self {
71        Self::Internal(msg.to_string())
72    }
73}
74
75impl From<dbn::Error> for Error {
76    fn from(dbn_err: dbn::Error) -> Self {
77        match dbn_err {
78            // Convert to our own error type.
79            dbn::Error::Io { source, .. } => Self::Io(source),
80            dbn_err => Self::Dbn(dbn_err),
81        }
82    }
83}
84
85#[cfg(feature = "historical")]
86impl std::fmt::Display for ApiError {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        let doc = if let Some(ref docs_url) = self.docs_url {
89            format!(" See {docs_url} for documentation.")
90        } else {
91            String::new()
92        };
93        let status = self.status_code;
94        let msg = &self.message;
95        if let Some(ref request_id) = self.request_id {
96            write!(f, "{request_id} failed with {status} {msg}{doc}")
97        } else {
98            write!(f, "{status} {msg}{doc}")
99        }
100    }
101}