marple_db/errors.rs
1use reqwest::{Method, StatusCode};
2use std::num::TryFromIntError;
3use thiserror::Error;
4
5/// Error type returned by the MarpleDB SDK.
6///
7/// `Transport` means no usable HTTP response was received, `Api` means the
8/// MarpleDB API returned a non-success status, and `Storage` covers direct
9/// pre-signed storage uploads/downloads.
10///
11/// ```
12/// # fn handle(error: marple_db::Error) {
13/// match error {
14/// marple_db::Error::Api { status, body, .. } => {
15/// eprintln!("API returned {status}: {body}");
16/// }
17/// error if error.status().is_some() => {
18/// eprintln!("HTTP-like error: {:?}", error.status());
19/// }
20/// error => eprintln!("{error}"),
21/// }
22/// # }
23/// ```
24#[non_exhaustive]
25#[derive(Debug, Error)]
26pub enum Error {
27 /// The SDK was configured with invalid input.
28 #[error("invalid configuration: {0}")]
29 Config(String),
30
31 /// Building an HTTP header failed.
32 #[error("invalid HTTP header value")]
33 Header(#[from] reqwest::header::InvalidHeaderValue),
34
35 /// A request failed before receiving an API response.
36 #[error("HTTP transport error on {method} {endpoint}")]
37 Transport {
38 /// HTTP method used for the request.
39 method: Method,
40 /// API endpoint or URL being requested.
41 endpoint: String,
42 /// Underlying reqwest error.
43 #[source]
44 source: reqwest::Error,
45 },
46
47 /// The MarpleDB API returned a non-success HTTP status.
48 #[error("MarpleDB API returned {status} on {method} {endpoint}: {body}")]
49 Api {
50 /// HTTP method used for the request.
51 method: Method,
52 /// API endpoint being requested.
53 endpoint: String,
54 /// Response status code.
55 status: StatusCode,
56 /// Response body text.
57 body: String,
58 },
59
60 /// Direct storage upload or download failed.
61 #[error("storage transfer failed: {context}")]
62 Storage {
63 /// Human-readable storage operation context.
64 context: String,
65 /// HTTP status code when the storage service responded with one.
66 status: Option<StatusCode>,
67 /// Response body text when available.
68 body: Option<String>,
69 /// Underlying reqwest error when the request failed before a response.
70 #[source]
71 source: Option<reqwest::Error>,
72 },
73
74 /// A stream with the requested name was not found.
75 #[error("stream {name:?} not found")]
76 StreamNotFound {
77 /// Requested stream name.
78 name: String,
79 },
80
81 /// A stream with the requested id was not found.
82 #[error("stream {id} not found")]
83 StreamIdNotFound {
84 /// Requested stream id.
85 id: i32,
86 },
87
88 /// The dataset has no original-file backup available for download.
89 #[error("dataset {id} has no backup available")]
90 NoBackup {
91 /// Dataset id.
92 id: i32,
93 },
94
95 /// Import polling reached its timeout before a terminal status.
96 #[error("ingestion timed out after {timeout_secs}s, last status: {last_status}")]
97 ImportTimeout {
98 /// Timeout in seconds.
99 timeout_secs: u64,
100 /// Last observed import status.
101 last_status: String,
102 },
103
104 /// Import polling reached a failed terminal status.
105 #[error("ingestion failed for dataset {id}: {message}")]
106 ImportFailed {
107 /// Dataset id.
108 id: i32,
109 /// Failure message from the API, if present.
110 message: String,
111 },
112
113 /// The API returned a response that does not match the SDK protocol.
114 #[error("invalid server response: {0}")]
115 Protocol(String),
116
117 /// Local filesystem I/O failed.
118 #[error("I/O error")]
119 Io(#[from] std::io::Error),
120
121 /// URL parsing failed.
122 #[error("URL parse error")]
123 Url(#[from] url::ParseError),
124
125 /// JSON serialization or deserialization failed.
126 #[error("JSON error")]
127 Json(#[from] serde_json::Error),
128
129 /// Integer conversion failed.
130 #[error("integer conversion failed")]
131 IntegerConversion(#[from] TryFromIntError),
132}
133
134impl Error {
135 /// Returns the HTTP status for API or storage responses that provided one.
136 pub fn status(&self) -> Option<StatusCode> {
137 match self {
138 Self::Api { status, .. } => Some(*status),
139 Self::Storage { status, .. } => *status,
140 _ => None,
141 }
142 }
143}
144
145/// Result type returned by the MarpleDB SDK.
146pub type Result<T> = std::result::Result<T, Error>;