fix(connector): implement ConnectorErrorExt for error_stack::Result<T, ConnectorError> (#1382)

Co-authored-by: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com>
This commit is contained in:
Abhishek Marrivagu
2023-06-16 18:51:29 +05:30
committed by GitHub
parent a7ac4af5d9
commit 3ef1d2935e
12 changed files with 143 additions and 133 deletions

View File

@ -129,7 +129,7 @@ pub async fn accept_dispute(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_dispute_failed_response())
.to_dispute_failed_response()
.attach_printable("Failed while calling accept dispute connector api")?;
let accept_dispute_response =
response
@ -236,7 +236,7 @@ pub async fn submit_evidence(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_payment_failed_response())
.to_dispute_failed_response()
.attach_printable("Failed while calling submit evidence connector api")?;
let submit_evidence_response =
response
@ -272,7 +272,7 @@ pub async fn submit_evidence(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_payment_failed_response())
.to_dispute_failed_response()
.attach_printable("Failed while calling defend dispute connector api")?;
let defend_dispute_response = defend_response.response.map_err(|err| {
errors::ApiErrorResponse::ExternalConnectorError {

View File

@ -43,143 +43,153 @@ impl<T> StorageErrorExt<T, errors::ApiErrorResponse>
}
}
pub trait ConnectorErrorExt {
pub trait ConnectorErrorExt<T> {
#[track_caller]
fn to_refund_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
fn to_refund_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse>;
#[track_caller]
fn to_payment_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
fn to_payment_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse>;
#[track_caller]
fn to_verify_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
fn to_verify_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse>;
#[track_caller]
fn to_dispute_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse>;
fn to_dispute_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse>;
}
impl ConnectorErrorExt for error_stack::Report<errors::ConnectorError> {
fn to_refund_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse> {
let data = match self.current_context() {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|error| logger::error!(%error,"Failed to convert response to JSON"),
)
.ok(),
Err(error) => {
logger::error!(%error,"Failed to convert response to UTF8 string");
None
impl<T> ConnectorErrorExt<T> for error_stack::Result<T, errors::ConnectorError> {
fn to_refund_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse> {
self.map_err(|err| {
let data = match err.current_context() {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|error| logger::error!(%error,"Failed to convert response to JSON"),
)
.ok(),
Err(error) => {
logger::error!(%error,"Failed to convert response to UTF8 string");
None
}
}
}
}
_ => None,
};
self.change_context(errors::ApiErrorResponse::RefundFailed { data })
_ => None,
};
err.change_context(errors::ApiErrorResponse::RefundFailed { data })
})
}
fn to_payment_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse> {
let error = match self.current_context() {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
let data = match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|error| logger::error!(%error,"Failed to convert response to JSON"),
)
.ok(),
Err(error) => {
logger::error!(%error,"Failed to convert response to UTF8 string");
None
fn to_payment_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse> {
self.map_err(|err| {
let error = match err.current_context() {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
let data = match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|error| logger::error!(%error,"Failed to convert response to JSON"),
)
.ok(),
Err(error) => {
logger::error!(%error,"Failed to convert response to UTF8 string");
None
}
};
errors::ApiErrorResponse::PaymentAuthorizationFailed { data }
}
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
errors::ConnectorError::MissingRequiredFields { field_names } => {
errors::ApiErrorResponse::MissingRequiredFields { field_names: field_names.to_vec() }
}
errors::ConnectorError::NotImplemented(reason) => {
errors::ApiErrorResponse::NotImplemented {
message: errors::api_error_response::NotImplementedMessage::Reason(
reason.to_string(),
),
}
};
errors::ApiErrorResponse::PaymentAuthorizationFailed { data }
}
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
errors::ConnectorError::MissingRequiredFields { field_names } => {
errors::ApiErrorResponse::MissingRequiredFields { field_names: field_names.to_vec() }
}
errors::ConnectorError::NotImplemented(reason) => {
errors::ApiErrorResponse::NotImplemented {
message: errors::api_error_response::NotImplementedMessage::Reason(
reason.to_string(),
),
}
}
errors::ConnectorError::MismatchedPaymentData => {
errors::ApiErrorResponse::InvalidDataValue {
field_name:
"payment_method_data, payment_method_type and payment_experience does not match",
errors::ConnectorError::MismatchedPaymentData => {
errors::ApiErrorResponse::InvalidDataValue {
field_name:
"payment_method_data, payment_method_type and payment_experience does not match",
}
},
errors::ConnectorError::NotSupported { message, connector, payment_experience } => {
errors::ApiErrorResponse::NotSupported { message: format!("{message} is not supported by {connector} through payment experience {payment_experience}") }
},
errors::ConnectorError::FlowNotSupported{ flow, connector } => {
errors::ApiErrorResponse::FlowNotSupported { flow: flow.to_owned(), connector: connector.to_owned() }
}
},
errors::ConnectorError::NotSupported { message, connector, payment_experience } => {
errors::ApiErrorResponse::NotSupported { message: format!("{message} is not supported by {connector} through payment experience {payment_experience}") }
},
errors::ConnectorError::FlowNotSupported{ flow, connector } => {
errors::ApiErrorResponse::FlowNotSupported { flow: flow.to_owned(), connector: connector.to_owned() }
}
_ => errors::ApiErrorResponse::InternalServerError,
};
self.change_context(error)
_ => errors::ApiErrorResponse::InternalServerError,
};
err.change_context(error)
})
}
fn to_verify_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse> {
let error = self.current_context();
let data = match error {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
let error_response = match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(|err| logger::error!(%err, "Failed to convert response to JSON"))
.ok(),
Err(err) => {
logger::error!(%err, "Failed to convert response to UTF8 string");
None
fn to_verify_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse> {
self.map_err(|err| {
let error = err.current_context();
let data = match error {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
let error_response = match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|err| logger::error!(%err, "Failed to convert response to JSON"),
)
.ok(),
Err(err) => {
logger::error!(%err, "Failed to convert response to UTF8 string");
None
}
};
errors::ApiErrorResponse::PaymentAuthorizationFailed {
data: error_response,
}
};
errors::ApiErrorResponse::PaymentAuthorizationFailed {
data: error_response,
}
}
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
_ => {
logger::error!(%error,"Verify flow failed");
errors::ApiErrorResponse::PaymentAuthorizationFailed { data: None }
}
};
self.change_context(data)
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
_ => {
logger::error!(%error,"Verify flow failed");
errors::ApiErrorResponse::PaymentAuthorizationFailed { data: None }
}
};
err.change_context(data)
})
}
fn to_dispute_failed_response(self) -> error_stack::Report<errors::ApiErrorResponse> {
let error = match self.current_context() {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
let data = match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|error| logger::error!(%error,"Failed to convert response to JSON"),
)
.ok(),
Err(error) => {
logger::error!(%error,"Failed to convert response to UTF8 string");
None
}
};
errors::ApiErrorResponse::DisputeFailed { data }
}
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
errors::ConnectorError::MissingRequiredFields { field_names } => {
errors::ApiErrorResponse::MissingRequiredFields {
field_names: field_names.to_vec(),
fn to_dispute_failed_response(self) -> error_stack::Result<T, errors::ApiErrorResponse> {
self.map_err(|err| {
let error = match err.current_context() {
errors::ConnectorError::ProcessingStepFailed(Some(bytes)) => {
let response_str = std::str::from_utf8(bytes);
let data = match response_str {
Ok(s) => serde_json::from_str(s)
.map_err(
|error| logger::error!(%error,"Failed to convert response to JSON"),
)
.ok(),
Err(error) => {
logger::error!(%error,"Failed to convert response to UTF8 string");
None
}
};
errors::ApiErrorResponse::DisputeFailed { data }
}
}
_ => errors::ApiErrorResponse::InternalServerError,
};
self.change_context(error)
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
errors::ConnectorError::MissingRequiredFields { field_names } => {
errors::ApiErrorResponse::MissingRequiredFields {
field_names: field_names.to_vec(),
}
}
_ => errors::ApiErrorResponse::InternalServerError,
};
err.change_context(error)
})
}
}

View File

@ -48,7 +48,7 @@ pub async fn create_connector_customer<F: Clone, T: Clone>(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
metrics::CONNECTOR_CUSTOMER_CREATE.add(
&metrics::CONTEXT,

View File

@ -140,7 +140,7 @@ impl types::PaymentsAuthorizeRouterData {
connector_integration
.execute_pretasks(self, state)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
metrics::EXECUTE_PRETASK_COUNT.add(
&metrics::CONTEXT,
@ -165,7 +165,7 @@ impl types::PaymentsAuthorizeRouterData {
call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
let pm_id = tokenization::save_payment_method(
state,
@ -266,7 +266,7 @@ pub async fn authorize_preprocessing_steps<F: Clone>(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
metrics::PREPROCESSING_STEPS_COUNT.add(
&metrics::CONTEXT,

View File

@ -96,7 +96,7 @@ impl types::PaymentsCancelRouterData {
call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
Ok(resp)
}

View File

@ -89,7 +89,7 @@ impl types::PaymentsCaptureRouterData {
call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
Ok(resp)
}

View File

@ -104,7 +104,7 @@ impl types::PaymentsCompleteAuthorizeRouterData {
call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
Ok(resp)
}

View File

@ -89,7 +89,7 @@ impl types::PaymentsSyncRouterData {
call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
Ok(resp)
}

View File

@ -306,7 +306,7 @@ impl types::PaymentsSessionRouterData {
call_connector_action,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
Ok(resp)
}

View File

@ -133,7 +133,7 @@ impl types::VerifyRouterData {
call_connector_action,
)
.await
.map_err(|err| err.to_verify_failed_response())?;
.to_verify_failed_response()?;
let pm_id = tokenization::save_payment_method(
state,

View File

@ -229,7 +229,7 @@ pub async fn add_payment_method_token<F: Clone, T: Clone>(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_payment_failed_response())?;
.to_payment_failed_response()?;
metrics::CONNECTOR_PAYMENT_METHOD_TOKENIZATION.add(
&metrics::CONTEXT,

View File

@ -191,7 +191,7 @@ pub async fn trigger_refund_to_gateway(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_refund_failed_response())?
.to_refund_failed_response()?
} else {
router_data
};
@ -410,7 +410,7 @@ pub async fn sync_refund_with_gateway(
payments::CallConnectorAction::Trigger,
)
.await
.map_err(|error| error.to_refund_failed_response())?
.to_refund_failed_response()?
} else {
router_data
};