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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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