From 8127979f9a05f3bd9b4081fe02c5bac37c35c9a8 Mon Sep 17 00:00:00 2001 From: Reuben Wong Date: Tue, 26 Sep 2023 00:49:43 +0800 Subject: [PATCH] clone gitlab errors into marketstack --- Cargo.toml | 3 ++- src/api/error.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b385ce3..b3cf445 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,12 +11,13 @@ reqwest = { version = "~0.11.19", features = [ "blocking", "json", ], default-features = false, optional = true } -thiserror = { version = "^1.0.2", optional = true } +thiserror = { version = "^1.0.48", optional = true } http = "~0.2" serde = { version = "~1.0.103", features = ["derive"] } serde_json = "^1.0.25" serde_urlencoded = "~0.7" url = "^2.1" +bytes = "1.5.0" [dev-dependencies] dotenvy = "0.15.7" diff --git a/src/api/error.rs b/src/api/error.rs index 1a1cbc2..2c74b35 100644 --- a/src/api/error.rs +++ b/src/api/error.rs @@ -3,6 +3,7 @@ // This file may not be copied, modified, or distributed // except according to those terms. +use std::any; use std::error::Error; use thiserror::Error; @@ -90,3 +91,66 @@ where }, // TODO: implement pagination error } + +impl ApiError +where + E: Error + Send + Sync + 'static, +{ + /// Create an API error in a client error. + pub fn client(source: E) -> Self { + ApiError::Client { source } + } + + /// Wrap a client error in another wrapper. + pub fn map_client(self, f: F) -> ApiError + where + F: FnOnce(E) -> W, + W: Error + Send + Sync + 'static, + { + match self { + Self::Client { source } => ApiError::client(f(source)), + Self::UrlParse { source } => ApiError::UrlParse { source }, + Self::Body { source } => ApiError::Body { source }, + Self::Json { source } => ApiError::Json { source }, + Self::Marketstack { msg } => ApiError::Marketstack { msg }, + Self::MarketstackService { status, data } => { + ApiError::MarketstackService { status, data } + } + Self::MarketstackObject { obj } => ApiError::MarketstackObject { obj }, + Self::MarketstackUnrecognized { obj } => ApiError::MarketstackUnrecognized { obj }, + Self::DataType { source, typename } => ApiError::DataType { source, typename }, + } + } + + pub(crate) fn server_error(status: http::StatusCode, body: &bytes::Bytes) -> Self { + Self::MarketstackService { + status, + data: body.into_iter().copied().collect(), + } + } + + pub(crate) fn from_marketstack(value: serde_json::Value) -> Self { + let error_value = value + .pointer("/message") + .or_else(|| value.pointer("/error")); + + if let Some(error_value) = error_value { + if let Some(msg) = error_value.as_str() { + ApiError::Marketstack { msg: msg.into() } + } else { + ApiError::MarketstackObject { + obj: error_value.clone(), + } + } + } else { + ApiError::MarketstackUnrecognized { obj: value } + } + } + + pub(crate) fn data_type(source: serde_json::Error) -> Self { + ApiError::DataType { + source, + typename: any::type_name::(), + } + } +}