mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
refactor(errors): add parsing error types for context info (#911)
This commit is contained in:
@ -8,36 +8,23 @@
|
|||||||
///
|
///
|
||||||
pub type CustomResult<T, E> = error_stack::Result<T, E>;
|
pub type CustomResult<T, E> = error_stack::Result<T, E>;
|
||||||
|
|
||||||
macro_rules! impl_error_display {
|
/// Parsing Errors
|
||||||
($st: ident, $arg: tt) => {
|
#[derive(Debug, thiserror::Error)]
|
||||||
impl std::fmt::Display for $st {
|
pub enum ParsingError {
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
///Failed to parse enum
|
||||||
fmt.write_str(&format!(
|
#[error("Failed to parse enum: {0}")]
|
||||||
"{{ error_type: {:?}, error_description: {} }}",
|
EnumParseFailure(&'static str),
|
||||||
self, $arg
|
///Failed to parse struct
|
||||||
))
|
#[error("Failed to parse struct: {0}")]
|
||||||
}
|
StructParseFailure(&'static str),
|
||||||
}
|
/// Failed to encode data to given format
|
||||||
};
|
#[error("Failed to serialize to {0} format")]
|
||||||
|
EncodeError(&'static str),
|
||||||
|
/// Failed to parse data
|
||||||
|
#[error("Unknown error while parsing")]
|
||||||
|
UnknownError,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_error_type {
|
|
||||||
($name: ident, $arg: tt) => {
|
|
||||||
#[doc = ""]
|
|
||||||
#[doc = stringify!(Error variant $name)]
|
|
||||||
#[doc = stringify!(Custom error variant for $arg)]
|
|
||||||
#[doc = ""]
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct $name;
|
|
||||||
|
|
||||||
impl_error_display!($name, $arg);
|
|
||||||
|
|
||||||
impl std::error::Error for $name {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_error_type!(ParsingError, "Parsing error");
|
|
||||||
|
|
||||||
/// Validation errors.
|
/// Validation errors.
|
||||||
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
|
#[allow(missing_docs)] // Only to prevent warnings about struct fields not being documented
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
|||||||
@ -85,10 +85,12 @@ where
|
|||||||
Result<P, <P as TryFrom<&'e Self>>::Error>: ResultExt,
|
Result<P, <P as TryFrom<&'e Self>>::Error>: ResultExt,
|
||||||
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize,
|
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize,
|
||||||
{
|
{
|
||||||
serde_json::to_string(&P::try_from(self).change_context(errors::ParsingError)?)
|
serde_json::to_string(
|
||||||
.into_report()
|
&P::try_from(self).change_context(errors::ParsingError::UnknownError)?,
|
||||||
.change_context(errors::ParsingError)
|
)
|
||||||
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
.into_report()
|
||||||
|
.change_context(errors::ParsingError::EncodeError("string"))
|
||||||
|
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert_and_url_encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
fn convert_and_url_encode(&'e self) -> CustomResult<String, errors::ParsingError>
|
||||||
@ -97,10 +99,12 @@ where
|
|||||||
Result<P, <P as TryFrom<&'e Self>>::Error>: ResultExt,
|
Result<P, <P as TryFrom<&'e Self>>::Error>: ResultExt,
|
||||||
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize,
|
<Result<P, <P as TryFrom<&'e Self>>::Error> as ResultExt>::Ok: Serialize,
|
||||||
{
|
{
|
||||||
serde_urlencoded::to_string(&P::try_from(self).change_context(errors::ParsingError)?)
|
serde_urlencoded::to_string(
|
||||||
.into_report()
|
&P::try_from(self).change_context(errors::ParsingError::UnknownError)?,
|
||||||
.change_context(errors::ParsingError)
|
)
|
||||||
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
.into_report()
|
||||||
|
.change_context(errors::ParsingError::EncodeError("url-encoded"))
|
||||||
|
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check without two functions can we combine this
|
// Check without two functions can we combine this
|
||||||
@ -110,7 +114,7 @@ where
|
|||||||
{
|
{
|
||||||
serde_urlencoded::to_string(self)
|
serde_urlencoded::to_string(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::EncodeError("url-encoded"))
|
||||||
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +124,7 @@ where
|
|||||||
{
|
{
|
||||||
serde_json::to_string(self)
|
serde_json::to_string(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::EncodeError("json"))
|
||||||
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a request"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +134,7 @@ where
|
|||||||
{
|
{
|
||||||
serde_json::to_value(self)
|
serde_json::to_value(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::EncodeError("json-value"))
|
||||||
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a value"))
|
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,7 +144,7 @@ where
|
|||||||
{
|
{
|
||||||
serde_json::to_vec(self)
|
serde_json::to_vec(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::EncodeError("byte-vec"))
|
||||||
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a value"))
|
.attach_printable_lazy(|| format!("Unable to convert {self:?} to a value"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,13 +156,19 @@ pub trait BytesExt {
|
|||||||
///
|
///
|
||||||
/// Convert `bytes::Bytes` into type `<T>` using `serde::Deserialize`
|
/// Convert `bytes::Bytes` into type `<T>` using `serde::Deserialize`
|
||||||
///
|
///
|
||||||
fn parse_struct<'de, T>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_struct<'de, T>(
|
||||||
|
&'de self,
|
||||||
|
type_name: &'static str,
|
||||||
|
) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>;
|
T: Deserialize<'de>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BytesExt for bytes::Bytes {
|
impl BytesExt for bytes::Bytes {
|
||||||
fn parse_struct<'de, T>(&'de self, _type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_struct<'de, T>(
|
||||||
|
&'de self,
|
||||||
|
type_name: &'static str,
|
||||||
|
) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>,
|
T: Deserialize<'de>,
|
||||||
{
|
{
|
||||||
@ -166,7 +176,7 @@ impl BytesExt for bytes::Bytes {
|
|||||||
|
|
||||||
serde_json::from_slice::<T>(self.chunk())
|
serde_json::from_slice::<T>(self.chunk())
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::StructParseFailure(type_name))
|
||||||
.attach_printable_lazy(|| {
|
.attach_printable_lazy(|| {
|
||||||
let variable_type = std::any::type_name::<T>();
|
let variable_type = std::any::type_name::<T>();
|
||||||
format!("Unable to parse {variable_type} from bytes {self:?}")
|
format!("Unable to parse {variable_type} from bytes {self:?}")
|
||||||
@ -181,19 +191,25 @@ pub trait ByteSliceExt {
|
|||||||
///
|
///
|
||||||
/// Convert `[u8]` into type `<T>` by using `serde::Deserialize`
|
/// Convert `[u8]` into type `<T>` by using `serde::Deserialize`
|
||||||
///
|
///
|
||||||
fn parse_struct<'de, T>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_struct<'de, T>(
|
||||||
|
&'de self,
|
||||||
|
type_name: &'static str,
|
||||||
|
) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>;
|
T: Deserialize<'de>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ByteSliceExt for [u8] {
|
impl ByteSliceExt for [u8] {
|
||||||
fn parse_struct<'de, T>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_struct<'de, T>(
|
||||||
|
&'de self,
|
||||||
|
type_name: &'static str,
|
||||||
|
) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>,
|
T: Deserialize<'de>,
|
||||||
{
|
{
|
||||||
serde_json::from_slice(self)
|
serde_json::from_slice(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::StructParseFailure(type_name))
|
||||||
.attach_printable_lazy(|| format!("Unable to parse {type_name} from &[u8] {:?}", &self))
|
.attach_printable_lazy(|| format!("Unable to parse {type_name} from &[u8] {:?}", &self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,13 +221,13 @@ pub trait ValueExt {
|
|||||||
///
|
///
|
||||||
/// Convert `serde_json::Value` into type `<T>` by using `serde::Deserialize`
|
/// Convert `serde_json::Value` into type `<T>` by using `serde::Deserialize`
|
||||||
///
|
///
|
||||||
fn parse_value<T>(self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_value<T>(self, type_name: &'static str) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned;
|
T: serde::de::DeserializeOwned;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ValueExt for serde_json::Value {
|
impl ValueExt for serde_json::Value {
|
||||||
fn parse_value<T>(self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_value<T>(self, type_name: &'static str) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -221,7 +237,7 @@ impl ValueExt for serde_json::Value {
|
|||||||
);
|
);
|
||||||
serde_json::from_value::<T>(self)
|
serde_json::from_value::<T>(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::StructParseFailure(type_name))
|
||||||
.attach_printable_lazy(|| debug)
|
.attach_printable_lazy(|| debug)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +246,7 @@ impl<MaskingStrategy> ValueExt for Secret<serde_json::Value, MaskingStrategy>
|
|||||||
where
|
where
|
||||||
MaskingStrategy: Strategy<serde_json::Value>,
|
MaskingStrategy: Strategy<serde_json::Value>,
|
||||||
{
|
{
|
||||||
fn parse_value<T>(self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_value<T>(self, type_name: &'static str) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
@ -245,7 +261,7 @@ pub trait StringExt<T> {
|
|||||||
///
|
///
|
||||||
/// Convert `String` into type `<T>` (which being an `enum`)
|
/// Convert `String` into type `<T>` (which being an `enum`)
|
||||||
///
|
///
|
||||||
fn parse_enum(self, enum_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_enum(self, enum_name: &'static str) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: std::str::FromStr,
|
T: std::str::FromStr,
|
||||||
// Requirement for converting the `Err` variant of `FromStr` to `Report<Err>`
|
// Requirement for converting the `Err` variant of `FromStr` to `Report<Err>`
|
||||||
@ -254,30 +270,36 @@ pub trait StringExt<T> {
|
|||||||
///
|
///
|
||||||
/// Convert `serde_json::Value` into type `<T>` by using `serde::Deserialize`
|
/// Convert `serde_json::Value` into type `<T>` by using `serde::Deserialize`
|
||||||
///
|
///
|
||||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_struct<'de>(
|
||||||
|
&'de self,
|
||||||
|
type_name: &'static str,
|
||||||
|
) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>;
|
T: Deserialize<'de>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> StringExt<T> for String {
|
impl<T> StringExt<T> for String {
|
||||||
fn parse_enum(self, enum_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_enum(self, enum_name: &'static str) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: std::str::FromStr,
|
T: std::str::FromStr,
|
||||||
<T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
<T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
T::from_str(&self)
|
T::from_str(&self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::EnumParseFailure(enum_name))
|
||||||
.attach_printable_lazy(|| format!("Invalid enum variant {self:?} for enum {enum_name}"))
|
.attach_printable_lazy(|| format!("Invalid enum variant {self:?} for enum {enum_name}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_struct<'de>(&'de self, type_name: &str) -> CustomResult<T, errors::ParsingError>
|
fn parse_struct<'de>(
|
||||||
|
&'de self,
|
||||||
|
type_name: &'static str,
|
||||||
|
) -> CustomResult<T, errors::ParsingError>
|
||||||
where
|
where
|
||||||
T: Deserialize<'de>,
|
T: Deserialize<'de>,
|
||||||
{
|
{
|
||||||
serde_json::from_str::<T>(self)
|
serde_json::from_str::<T>(self)
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::StructParseFailure(type_name))
|
||||||
.attach_printable_lazy(|| {
|
.attach_printable_lazy(|| {
|
||||||
format!("Unable to parse {type_name} from string {:?}", &self)
|
format!("Unable to parse {type_name} from string {:?}", &self)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -133,7 +133,7 @@ impl super::RedisConnectionPool {
|
|||||||
pub async fn get_and_deserialize_key<T>(
|
pub async fn get_and_deserialize_key<T>(
|
||||||
&self,
|
&self,
|
||||||
key: &str,
|
key: &str,
|
||||||
type_name: &str,
|
type_name: &'static str,
|
||||||
) -> CustomResult<T, errors::RedisError>
|
) -> CustomResult<T, errors::RedisError>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
@ -380,7 +380,7 @@ impl super::RedisConnectionPool {
|
|||||||
&self,
|
&self,
|
||||||
key: &str,
|
key: &str,
|
||||||
field: &str,
|
field: &str,
|
||||||
type_name: &str,
|
type_name: &'static str,
|
||||||
) -> CustomResult<V, errors::RedisError>
|
) -> CustomResult<V, errors::RedisError>
|
||||||
where
|
where
|
||||||
V: serde::de::DeserializeOwned,
|
V: serde::de::DeserializeOwned,
|
||||||
|
|||||||
@ -735,7 +735,8 @@ fn get_webhook_object_from_body(
|
|||||||
.notification_items
|
.notification_items
|
||||||
.drain(..)
|
.drain(..)
|
||||||
.next()
|
.next()
|
||||||
.ok_or(errors::ParsingError)
|
// TODO: ParsingError doesn't seem to be an apt error for this case
|
||||||
|
.ok_or(errors::ParsingError::UnknownError)
|
||||||
.into_report()?;
|
.into_report()?;
|
||||||
|
|
||||||
Ok(item_object.notification_request_item)
|
Ok(item_object.notification_request_item)
|
||||||
|
|||||||
@ -106,7 +106,7 @@ impl StorageInterface for MockDb {}
|
|||||||
pub async fn get_and_deserialize_key<T>(
|
pub async fn get_and_deserialize_key<T>(
|
||||||
db: &dyn StorageInterface,
|
db: &dyn StorageInterface,
|
||||||
key: &str,
|
key: &str,
|
||||||
type_name: &str,
|
type_name: &'static str,
|
||||||
) -> common_utils::errors::CustomResult<T, redis_interface::errors::RedisError>
|
) -> common_utils::errors::CustomResult<T, redis_interface::errors::RedisError>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
|
|||||||
@ -48,7 +48,7 @@ impl ConnectorAccessToken for Store {
|
|||||||
let access_token: Option<types::AccessToken> = maybe_token
|
let access_token: Option<types::AccessToken> = maybe_token
|
||||||
.map(|token| token.parse_struct("AccessToken"))
|
.map(|token| token.parse_struct("AccessToken"))
|
||||||
.transpose()
|
.transpose()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::UnknownError)
|
||||||
.change_context(errors::StorageError::DeserializationFailed)?;
|
.change_context(errors::StorageError::DeserializationFailed)?;
|
||||||
|
|
||||||
Ok(access_token)
|
Ok(access_token)
|
||||||
|
|||||||
@ -83,7 +83,7 @@ impl ProcessTrackerBatch {
|
|||||||
.as_str()
|
.as_str()
|
||||||
.parse()
|
.parse()
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::UnknownError)
|
||||||
.change_context(errors::ProcessTrackerError::DeserializationFailed)?,
|
.change_context(errors::ProcessTrackerError::DeserializationFailed)?,
|
||||||
)
|
)
|
||||||
.into_report()
|
.into_report()
|
||||||
@ -105,7 +105,7 @@ impl ProcessTrackerBatch {
|
|||||||
|
|
||||||
let trackers = serde_json::from_str::<Vec<ProcessTracker>>(trackers.as_str())
|
let trackers = serde_json::from_str::<Vec<ProcessTracker>>(trackers.as_str())
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::UnknownError)
|
||||||
.attach_printable_lazy(|| {
|
.attach_printable_lazy(|| {
|
||||||
format!("Unable to parse trackers from JSON string: {trackers:?}")
|
format!("Unable to parse trackers from JSON string: {trackers:?}")
|
||||||
})
|
})
|
||||||
|
|||||||
@ -76,7 +76,7 @@ pub fn generate_id(length: usize, prefix: &str) -> String {
|
|||||||
pub trait ConnectorResponseExt: Sized {
|
pub trait ConnectorResponseExt: Sized {
|
||||||
fn get_response(self) -> RouterResult<types::Response>;
|
fn get_response(self) -> RouterResult<types::Response>;
|
||||||
fn get_error_response(self) -> RouterResult<types::Response>;
|
fn get_error_response(self) -> RouterResult<types::Response>;
|
||||||
fn get_response_inner<T: DeserializeOwned>(self, type_name: &str) -> RouterResult<T> {
|
fn get_response_inner<T: DeserializeOwned>(self, type_name: &'static str) -> RouterResult<T> {
|
||||||
self.get_response()?
|
self.get_response()?
|
||||||
.response
|
.response
|
||||||
.parse_struct(type_name)
|
.parse_struct(type_name)
|
||||||
|
|||||||
@ -57,11 +57,11 @@ where
|
|||||||
{
|
{
|
||||||
let value = self
|
let value = self
|
||||||
.get_required_value(enum_name)
|
.get_required_value(enum_name)
|
||||||
.change_context(errors::ParsingError)?;
|
.change_context(errors::ParsingError::UnknownError)?;
|
||||||
|
|
||||||
E::from_str(value.as_ref())
|
E::from_str(value.as_ref())
|
||||||
.into_report()
|
.into_report()
|
||||||
.change_context(errors::ParsingError)
|
.change_context(errors::ParsingError::UnknownError)
|
||||||
.attach_printable_lazy(|| format!("Invalid {{ {enum_name}: {value:?} }} "))
|
.attach_printable_lazy(|| format!("Invalid {{ {enum_name}: {value:?} }} "))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ where
|
|||||||
{
|
{
|
||||||
let value = self
|
let value = self
|
||||||
.get_required_value(type_name)
|
.get_required_value(type_name)
|
||||||
.change_context(errors::ParsingError)?;
|
.change_context(errors::ParsingError::UnknownError)?;
|
||||||
value.parse_value(type_name)
|
value.parse_value(type_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user