nautilus_derive/http/
error.rs1use nautilus_network::http::HttpClientError;
19use serde_json::Value;
20use thiserror::Error;
21
22use crate::signing::auth::AuthError;
23
24pub type Result<T> = std::result::Result<T, DeriveHttpError>;
26
27#[derive(Debug, Error)]
29pub enum DeriveHttpError {
30 #[error("transport error: {0}")]
32 Transport(String),
33
34 #[error("HTTP {status}: {message}")]
37 Http {
38 status: u16,
40 message: String,
42 },
43
44 #[error("JSON-RPC error {code}: {message}")]
46 JsonRpc {
47 code: i64,
49 message: String,
51 data: Option<Value>,
53 },
54
55 #[error("missing `result` in JSON-RPC response for `{method}`")]
57 MissingResult {
58 method: String,
60 },
61
62 #[error("decode error: {0}")]
64 Decode(String),
65
66 #[error("serde error: {0}")]
68 Serde(#[from] serde_json::Error),
69
70 #[error("auth error: {0}")]
72 Auth(#[from] AuthError),
73
74 #[error("missing credentials for private endpoint `{method}`")]
76 MissingCredentials {
77 method: String,
79 },
80}
81
82impl DeriveHttpError {
83 #[must_use]
85 pub fn transport(msg: impl Into<String>) -> Self {
86 Self::Transport(msg.into())
87 }
88
89 #[must_use]
91 pub fn http(status: u16, message: impl Into<String>) -> Self {
92 Self::Http {
93 status,
94 message: message.into(),
95 }
96 }
97
98 #[must_use]
100 pub fn decode(msg: impl Into<String>) -> Self {
101 Self::Decode(msg.into())
102 }
103
104 #[must_use]
108 pub fn is_transport_error(&self) -> bool {
109 matches!(self, Self::Transport(_))
110 }
111}
112
113impl From<HttpClientError> for DeriveHttpError {
114 fn from(value: HttpClientError) -> Self {
115 Self::Transport(value.to_string())
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use rstest::rstest;
122 use serde_json::json;
123
124 use super::*;
125
126 #[rstest]
127 fn test_transport_is_transport_error() {
128 assert!(DeriveHttpError::transport("conn reset").is_transport_error());
129 }
130
131 #[rstest]
132 fn test_http_is_not_transport_error() {
133 assert!(!DeriveHttpError::http(503, "service unavailable").is_transport_error());
134 }
135
136 #[rstest]
137 fn test_jsonrpc_error_carries_code_and_data() {
138 let err = DeriveHttpError::JsonRpc {
139 code: -32602,
140 message: "Invalid params".to_string(),
141 data: Some(json!({"field": "currency"})),
142 };
143 let text = err.to_string();
144 assert!(text.contains("-32602"));
145 assert!(text.contains("Invalid params"));
146 assert!(!err.is_transport_error());
147 }
148
149 #[rstest]
150 fn test_missing_credentials_names_method() {
151 let err = DeriveHttpError::MissingCredentials {
152 method: "private/order".to_string(),
153 };
154 assert!(err.to_string().contains("private/order"));
155 }
156
157 #[rstest]
158 fn test_http_client_error_maps_to_transport() {
159 let upstream = HttpClientError::Error("boom".to_string());
160 let mapped: DeriveHttpError = upstream.into();
161 assert!(mapped.is_transport_error());
162 }
163}