mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-27 19:46:48 +08:00
feat(router): send 2xx payments response for all the connector http responses (2xx, 4xx etc.) (#1924)
This commit is contained in:
committed by
GitHub
parent
35963e279a
commit
0ab6827f6c
@ -71,6 +71,28 @@ where
|
||||
),
|
||||
}
|
||||
}
|
||||
Ok(api::ApplicationResponse::JsonWithHeaders((response, headers))) => {
|
||||
let response = S::try_from(response);
|
||||
match response {
|
||||
Ok(response) => match serde_json::to_string(&response) {
|
||||
Ok(res) => api::http_response_json_with_headers(res, headers),
|
||||
Err(_) => api::http_response_err(
|
||||
r#"{
|
||||
"error": {
|
||||
"message": "Error serializing response from connector"
|
||||
}
|
||||
}"#,
|
||||
),
|
||||
},
|
||||
Err(_) => api::http_response_err(
|
||||
r#"{
|
||||
"error": {
|
||||
"message": "Error converting juspay response to stripe response"
|
||||
}
|
||||
}"#,
|
||||
),
|
||||
}
|
||||
}
|
||||
Ok(api::ApplicationResponse::StatusOk) => api::http_response_ok(),
|
||||
Ok(api::ApplicationResponse::TextPlain(text)) => api::http_response_plaintext(text),
|
||||
Ok(api::ApplicationResponse::FileData((file_data, content_type))) => {
|
||||
|
||||
@ -39,7 +39,7 @@ use crate::{
|
||||
self, api, domain,
|
||||
storage::{self, enums as storage_enums, ProcessTrackerExt},
|
||||
},
|
||||
utils::{Encode, OptionExt, ValueExt},
|
||||
utils::{add_connector_http_status_code_metrics, Encode, OptionExt, ValueExt},
|
||||
};
|
||||
|
||||
#[instrument(skip_all, fields(payment_id, merchant_id))]
|
||||
@ -51,7 +51,7 @@ pub async fn payments_operation_core<F, Req, Op, FData>(
|
||||
req: Req,
|
||||
call_connector_action: CallConnectorAction,
|
||||
auth_flow: services::AuthFlow,
|
||||
) -> RouterResult<(PaymentData<F>, Req, Option<domain::Customer>)>
|
||||
) -> RouterResult<(PaymentData<F>, Req, Option<domain::Customer>, Option<u16>)>
|
||||
where
|
||||
F: Send + Clone + Sync,
|
||||
Req: Authenticate,
|
||||
@ -151,6 +151,8 @@ where
|
||||
)
|
||||
.await?;
|
||||
|
||||
let mut connector_http_status_code = None;
|
||||
|
||||
if let Some(connector_details) = connector {
|
||||
payment_data = match connector_details {
|
||||
api::ConnectorCallType::Single(connector) => {
|
||||
@ -172,6 +174,9 @@ where
|
||||
|
||||
let operation = Box::new(PaymentResponse);
|
||||
let db = &*state.store;
|
||||
connector_http_status_code = router_data.connector_http_status_code;
|
||||
//add connector http status code metrics
|
||||
add_connector_http_status_code_metrics(connector_http_status_code);
|
||||
operation
|
||||
.to_post_update_tracker()?
|
||||
.update_tracker(
|
||||
@ -226,7 +231,7 @@ where
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok((payment_data, req, customer))
|
||||
Ok((payment_data, req, customer, connector_http_status_code))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@ -256,7 +261,7 @@ where
|
||||
// To perform router related operation for PaymentResponse
|
||||
PaymentResponse: Operation<F, FData>,
|
||||
{
|
||||
let (payment_data, req, customer) = payments_operation_core(
|
||||
let (payment_data, req, customer, connector_http_status_code) = payments_operation_core(
|
||||
state,
|
||||
merchant_account,
|
||||
key_store,
|
||||
@ -275,6 +280,7 @@ where
|
||||
&state.conf.server,
|
||||
operation,
|
||||
&state.conf.connector_request_reference_id_config,
|
||||
connector_http_status_code,
|
||||
)
|
||||
}
|
||||
|
||||
@ -373,6 +379,7 @@ pub trait PaymentRedirectFlow: Sync {
|
||||
|
||||
let payments_response = match response? {
|
||||
services::ApplicationResponse::Json(response) => Ok(response),
|
||||
services::ApplicationResponse::JsonWithHeaders((response, _)) => Ok(response),
|
||||
_ => Err(errors::ApiErrorResponse::InternalServerError)
|
||||
.into_report()
|
||||
.attach_printable("Failed to get the response in json"),
|
||||
|
||||
@ -2462,6 +2462,7 @@ pub fn router_data_type_conversion<F1, F2, Req1, Req2, Res1, Res2>(
|
||||
#[cfg(feature = "payouts")]
|
||||
quote_id: None,
|
||||
test_mode: router_data.test_mode,
|
||||
connector_http_status_code: router_data.connector_http_status_code,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use async_trait::async_trait;
|
||||
use common_utils::fp_utils;
|
||||
use error_stack::ResultExt;
|
||||
use router_derive;
|
||||
|
||||
@ -51,9 +50,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthorizeData
|
||||
.mandate_id
|
||||
.or_else(|| router_data.request.mandate_id.clone());
|
||||
|
||||
let router_response = router_data.response.clone();
|
||||
let connector = router_data.connector.clone();
|
||||
|
||||
payment_data = payment_response_update_tracker(
|
||||
db,
|
||||
payment_id,
|
||||
@ -63,22 +59,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsAuthorizeData
|
||||
)
|
||||
.await?;
|
||||
|
||||
router_response.map(|_| ()).or_else(|error_response| {
|
||||
fp_utils::when(
|
||||
!(200..300).contains(&error_response.status_code)
|
||||
&& !(500..=511).contains(&error_response.status_code),
|
||||
|| {
|
||||
Err(errors::ApiErrorResponse::ExternalConnectorError {
|
||||
code: error_response.code,
|
||||
message: error_response.message,
|
||||
connector,
|
||||
status_code: error_response.status_code,
|
||||
reason: error_response.reason,
|
||||
})
|
||||
},
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
@ -116,9 +96,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsSessionData>
|
||||
where
|
||||
F: 'b + Send,
|
||||
{
|
||||
let router_response = router_data.response.clone();
|
||||
let connector = router_data.connector.clone();
|
||||
|
||||
payment_data = payment_response_update_tracker(
|
||||
db,
|
||||
payment_id,
|
||||
@ -128,16 +105,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsSessionData>
|
||||
)
|
||||
.await?;
|
||||
|
||||
router_response.map_err(|error_response| {
|
||||
errors::ApiErrorResponse::ExternalConnectorError {
|
||||
message: error_response.message,
|
||||
code: error_response.code,
|
||||
status_code: error_response.status_code,
|
||||
reason: error_response.reason,
|
||||
connector,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
@ -157,9 +124,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCaptureData>
|
||||
where
|
||||
F: 'b + Send,
|
||||
{
|
||||
let router_response = router_data.response.clone();
|
||||
let connector = router_data.connector.clone();
|
||||
|
||||
payment_data = payment_response_update_tracker(
|
||||
db,
|
||||
payment_id,
|
||||
@ -169,16 +133,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCaptureData>
|
||||
)
|
||||
.await?;
|
||||
|
||||
router_response.map_err(|error_response| {
|
||||
errors::ApiErrorResponse::ExternalConnectorError {
|
||||
message: error_response.message,
|
||||
code: error_response.code,
|
||||
status_code: error_response.status_code,
|
||||
reason: error_response.reason,
|
||||
connector,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
@ -197,9 +151,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCancelData> f
|
||||
where
|
||||
F: 'b + Send,
|
||||
{
|
||||
let router_response = router_data.response.clone();
|
||||
let connector = router_data.connector.clone();
|
||||
|
||||
payment_data = payment_response_update_tracker(
|
||||
db,
|
||||
payment_id,
|
||||
@ -209,16 +160,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::PaymentsCancelData> f
|
||||
)
|
||||
.await?;
|
||||
|
||||
router_response.map_err(|error_response| {
|
||||
errors::ApiErrorResponse::ExternalConnectorError {
|
||||
message: error_response.message,
|
||||
code: error_response.code,
|
||||
status_code: error_response.status_code,
|
||||
reason: error_response.reason,
|
||||
connector,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
@ -242,9 +183,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::VerifyRequestData> fo
|
||||
// .map(api_models::payments::MandateIds::new)
|
||||
});
|
||||
|
||||
let router_response = router_data.response.clone();
|
||||
let connector = router_data.connector.clone();
|
||||
|
||||
payment_data = payment_response_update_tracker(
|
||||
db,
|
||||
payment_id,
|
||||
@ -254,16 +192,6 @@ impl<F: Clone> PostUpdateTracker<F, PaymentData<F>, types::VerifyRequestData> fo
|
||||
)
|
||||
.await?;
|
||||
|
||||
router_response.map_err(|error_response| {
|
||||
errors::ApiErrorResponse::ExternalConnectorError {
|
||||
message: error_response.message,
|
||||
code: error_response.code,
|
||||
status_code: error_response.status_code,
|
||||
reason: error_response.reason,
|
||||
connector,
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(payment_data)
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,6 +138,7 @@ where
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
|
||||
Ok(router_data)
|
||||
@ -148,6 +149,7 @@ where
|
||||
Self: Sized,
|
||||
Op: Debug,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn generate_response(
|
||||
req: Option<Req>,
|
||||
data: D,
|
||||
@ -156,6 +158,7 @@ where
|
||||
server: &Server,
|
||||
operation: Op,
|
||||
connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig,
|
||||
connector_http_status_code: Option<u16>,
|
||||
) -> RouterResponse<Self>;
|
||||
}
|
||||
|
||||
@ -164,6 +167,7 @@ where
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn generate_response(
|
||||
req: Option<Req>,
|
||||
payment_data: PaymentData<F>,
|
||||
@ -172,6 +176,7 @@ where
|
||||
server: &Server,
|
||||
operation: Op,
|
||||
connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig,
|
||||
connector_http_status_code: Option<u16>,
|
||||
) -> RouterResponse<Self> {
|
||||
payments_to_payments_response(
|
||||
req,
|
||||
@ -192,6 +197,7 @@ where
|
||||
payment_data.frm_message,
|
||||
payment_data.setup_mandate,
|
||||
connector_request_reference_id_config,
|
||||
connector_http_status_code,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -202,6 +208,7 @@ where
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn generate_response(
|
||||
_req: Option<Req>,
|
||||
payment_data: PaymentData<F>,
|
||||
@ -210,8 +217,10 @@ where
|
||||
_server: &Server,
|
||||
_operation: Op,
|
||||
_connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig,
|
||||
_connector_http_status_code: Option<u16>,
|
||||
) -> RouterResponse<Self> {
|
||||
Ok(services::ApplicationResponse::Json(Self {
|
||||
Ok(services::ApplicationResponse::JsonWithHeaders((
|
||||
Self {
|
||||
session_token: payment_data.sessions_token,
|
||||
payment_id: payment_data.payment_attempt.payment_id,
|
||||
client_secret: payment_data
|
||||
@ -219,7 +228,9 @@ where
|
||||
.client_secret
|
||||
.get_required_value("client_secret")?
|
||||
.into(),
|
||||
}))
|
||||
},
|
||||
vec![],
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,6 +240,7 @@ where
|
||||
F: Clone,
|
||||
Op: Debug,
|
||||
{
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn generate_response(
|
||||
_req: Option<Req>,
|
||||
data: PaymentData<F>,
|
||||
@ -237,6 +249,7 @@ where
|
||||
_server: &Server,
|
||||
_operation: Op,
|
||||
_connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig,
|
||||
_connector_http_status_code: Option<u16>,
|
||||
) -> RouterResponse<Self> {
|
||||
let additional_payment_method_data: Option<api_models::payments::AdditionalPaymentData> =
|
||||
data.payment_attempt
|
||||
@ -249,7 +262,8 @@ where
|
||||
})?;
|
||||
let payment_method_data_response =
|
||||
additional_payment_method_data.map(api::PaymentMethodDataResponse::from);
|
||||
Ok(services::ApplicationResponse::Json(Self {
|
||||
Ok(services::ApplicationResponse::JsonWithHeaders((
|
||||
Self {
|
||||
verify_id: Some(data.payment_intent.payment_id),
|
||||
merchant_id: Some(data.payment_intent.merchant_id),
|
||||
client_secret: data.payment_intent.client_secret.map(masking::Secret::new),
|
||||
@ -269,7 +283,9 @@ where
|
||||
payment_token: data.token,
|
||||
error_code: data.payment_attempt.error_code,
|
||||
error_message: data.payment_attempt.error_message,
|
||||
}))
|
||||
},
|
||||
vec![],
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,6 +312,7 @@ pub fn payments_to_payments_response<R, Op>(
|
||||
frm_message: Option<payments::FrmMessage>,
|
||||
mandate_data: Option<api_models::payments::MandateData>,
|
||||
connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig,
|
||||
connector_http_status_code: Option<u16>,
|
||||
) -> RouterResponse<api::PaymentsResponse>
|
||||
where
|
||||
Op: Debug,
|
||||
@ -356,6 +373,15 @@ where
|
||||
let payment_method_data_response =
|
||||
additional_payment_method_data.map(api::PaymentMethodDataResponse::from);
|
||||
|
||||
let headers = connector_http_status_code
|
||||
.map(|status_code| {
|
||||
vec![(
|
||||
"connector_http_status_code".to_string(),
|
||||
status_code.to_string(),
|
||||
)]
|
||||
})
|
||||
.unwrap_or(vec![]);
|
||||
|
||||
let output = Ok(match payment_request {
|
||||
Some(_request) => {
|
||||
if payments::is_start_pay(&operation) && redirection_data.is_some() {
|
||||
@ -445,7 +471,7 @@ where
|
||||
|
||||
let amount_captured = payment_intent.amount_captured.unwrap_or_default();
|
||||
let amount_capturable = Some(payment_attempt.amount - amount_captured);
|
||||
services::ApplicationResponse::Json(
|
||||
services::ApplicationResponse::JsonWithHeaders((
|
||||
response
|
||||
.set_payment_id(Some(payment_attempt.payment_id))
|
||||
.set_merchant_id(Some(payment_attempt.merchant_id))
|
||||
@ -531,10 +557,12 @@ where
|
||||
.set_connector_metadata(payment_intent.connector_metadata)
|
||||
.set_reference_id(payment_attempt.connector_response_reference_id)
|
||||
.to_owned(),
|
||||
)
|
||||
headers,
|
||||
))
|
||||
}
|
||||
}
|
||||
None => services::ApplicationResponse::Json(api::PaymentsResponse {
|
||||
None => services::ApplicationResponse::JsonWithHeaders((
|
||||
api::PaymentsResponse {
|
||||
payment_id: Some(payment_attempt.payment_id),
|
||||
merchant_id: Some(payment_attempt.merchant_id),
|
||||
status: payment_intent.status,
|
||||
@ -585,7 +613,9 @@ where
|
||||
allowed_payment_method_types: payment_intent.allowed_payment_method_types,
|
||||
reference_id: payment_attempt.connector_response_reference_id,
|
||||
..Default::default()
|
||||
}),
|
||||
},
|
||||
headers,
|
||||
)),
|
||||
});
|
||||
|
||||
metrics::PAYMENT_OPS_COUNT.add(
|
||||
|
||||
@ -182,6 +182,7 @@ pub async fn construct_payout_router_data<'a, F>(
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
|
||||
Ok(router_data)
|
||||
@ -289,6 +290,7 @@ pub async fn construct_refund_router_data<'a, F>(
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
|
||||
Ok(router_data)
|
||||
@ -506,6 +508,7 @@ pub async fn construct_accept_dispute_router_data<'a>(
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
Ok(router_data)
|
||||
}
|
||||
@ -580,6 +583,7 @@ pub async fn construct_submit_evidence_router_data<'a>(
|
||||
#[cfg(feature = "payouts")]
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
Ok(router_data)
|
||||
}
|
||||
@ -655,6 +659,7 @@ pub async fn construct_upload_file_router_data<'a>(
|
||||
#[cfg(feature = "payouts")]
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
Ok(router_data)
|
||||
}
|
||||
@ -732,6 +737,7 @@ pub async fn construct_defend_dispute_router_data<'a>(
|
||||
#[cfg(feature = "payouts")]
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
Ok(router_data)
|
||||
}
|
||||
@ -804,6 +810,7 @@ pub async fn construct_retrieve_file_router_data<'a>(
|
||||
#[cfg(feature = "payouts")]
|
||||
quote_id: None,
|
||||
test_mode,
|
||||
connector_http_status_code: None,
|
||||
};
|
||||
Ok(router_data)
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ pub async fn payments_incoming_webhook_flow<W: types::OutgoingWebhookType>(
|
||||
};
|
||||
|
||||
match payments_response {
|
||||
services::ApplicationResponse::Json(payments_response) => {
|
||||
services::ApplicationResponse::JsonWithHeaders((payments_response, _)) => {
|
||||
let payment_id = payments_response
|
||||
.payment_id
|
||||
.clone()
|
||||
@ -449,7 +449,7 @@ async fn bank_transfer_webhook_flow<W: types::OutgoingWebhookType>(
|
||||
};
|
||||
|
||||
match response? {
|
||||
services::ApplicationResponse::Json(payments_response) => {
|
||||
services::ApplicationResponse::JsonWithHeaders((payments_response, _)) => {
|
||||
let payment_id = payments_response
|
||||
.payment_id
|
||||
.clone()
|
||||
|
||||
@ -70,6 +70,12 @@ counter_metric!(REDIRECTION_TRIGGERED, GLOBAL_METER);
|
||||
// Connector Level Metric
|
||||
counter_metric!(REQUEST_BUILD_FAILURE, GLOBAL_METER);
|
||||
counter_metric!(UNIMPLEMENTED_FLOW, GLOBAL_METER);
|
||||
// Connector http status code metrics
|
||||
counter_metric!(CONNECTOR_HTTP_STATUS_CODE_1XX_COUNT, GLOBAL_METER);
|
||||
counter_metric!(CONNECTOR_HTTP_STATUS_CODE_2XX_COUNT, GLOBAL_METER);
|
||||
counter_metric!(CONNECTOR_HTTP_STATUS_CODE_3XX_COUNT, GLOBAL_METER);
|
||||
counter_metric!(CONNECTOR_HTTP_STATUS_CODE_4XX_COUNT, GLOBAL_METER);
|
||||
counter_metric!(CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT, GLOBAL_METER);
|
||||
|
||||
// Service Level
|
||||
counter_metric!(CARD_LOCKER_FAILURES, GLOBAL_METER);
|
||||
|
||||
@ -57,7 +57,8 @@ pub fn track_response_status_code<Q>(response: &ApplicationResponse<Q>) -> i64 {
|
||||
| ApplicationResponse::StatusOk
|
||||
| ApplicationResponse::TextPlain(_)
|
||||
| ApplicationResponse::Form(_)
|
||||
| ApplicationResponse::FileData(_) => 200,
|
||||
| ApplicationResponse::FileData(_)
|
||||
| ApplicationResponse::JsonWithHeaders(_) => 200,
|
||||
ApplicationResponse::JsonForRedirection(_) => 302,
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,8 @@ impl ProcessTrackerWorkflow for PaymentsSyncWorkflow {
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (payment_data, _, _) = payment_flows::payments_operation_core::<api::PSync, _, _, _>(
|
||||
let (payment_data, _, _, _) =
|
||||
payment_flows::payments_operation_core::<api::PSync, _, _, _>(
|
||||
state,
|
||||
merchant_account.clone(),
|
||||
key_store,
|
||||
|
||||
@ -285,7 +285,9 @@ where
|
||||
match response {
|
||||
Ok(body) => {
|
||||
let response = match body {
|
||||
Ok(body) => connector_integration
|
||||
Ok(body) => {
|
||||
let connector_http_status_code = Some(body.status_code);
|
||||
let mut data = connector_integration
|
||||
.handle_response(req, body)
|
||||
.map_err(|error| {
|
||||
if error.current_context()
|
||||
@ -301,8 +303,12 @@ where
|
||||
)
|
||||
}
|
||||
error
|
||||
})?,
|
||||
})?;
|
||||
data.connector_http_status_code = connector_http_status_code;
|
||||
data
|
||||
}
|
||||
Err(body) => {
|
||||
router_data.connector_http_status_code = Some(body.status_code);
|
||||
metrics::CONNECTOR_ERROR_RESPONSE_COUNT.add(
|
||||
&metrics::CONTEXT,
|
||||
1,
|
||||
@ -528,6 +534,7 @@ pub enum ApplicationResponse<R> {
|
||||
JsonForRedirection(api::RedirectionResponse),
|
||||
Form(Box<RedirectionFormData>),
|
||||
FileData((Vec<u8>, mime::Mime)),
|
||||
JsonWithHeaders((R, Vec<(String, String)>)),
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
@ -704,6 +711,18 @@ where
|
||||
)
|
||||
.respond_to(request)
|
||||
.map_into_boxed_body(),
|
||||
Ok(ApplicationResponse::JsonWithHeaders((response, headers))) => {
|
||||
match serde_json::to_string(&response) {
|
||||
Ok(res) => http_response_json_with_headers(res, headers),
|
||||
Err(_) => http_response_err(
|
||||
r#"{
|
||||
"error": {
|
||||
"message": "Error serializing response from connector"
|
||||
}
|
||||
}"#,
|
||||
),
|
||||
}
|
||||
}
|
||||
Err(error) => log_and_return_error_response(error),
|
||||
};
|
||||
|
||||
@ -769,6 +788,19 @@ pub fn http_response_json<T: body::MessageBody + 'static>(response: T) -> HttpRe
|
||||
.body(response)
|
||||
}
|
||||
|
||||
pub fn http_response_json_with_headers<T: body::MessageBody + 'static>(
|
||||
response: T,
|
||||
headers: Vec<(String, String)>,
|
||||
) -> HttpResponse {
|
||||
let mut response_builder = HttpResponse::Ok();
|
||||
for (name, value) in headers {
|
||||
response_builder.append_header((name, value));
|
||||
}
|
||||
response_builder
|
||||
.content_type(mime::APPLICATION_JSON)
|
||||
.body(response)
|
||||
}
|
||||
|
||||
pub fn http_response_plaintext<T: body::MessageBody + 'static>(res: T) -> HttpResponse {
|
||||
HttpResponse::Ok().content_type(mime::TEXT_PLAIN).body(res)
|
||||
}
|
||||
|
||||
@ -259,6 +259,7 @@ pub struct RouterData<Flow, Request, Response> {
|
||||
pub quote_id: Option<String>,
|
||||
|
||||
pub test_mode: Option<bool>,
|
||||
pub connector_http_status_code: Option<u16>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -919,6 +920,7 @@ impl<F1, F2, T1, T2> From<(&RouterData<F1, T1, PaymentsResponseData>, T2)>
|
||||
quote_id: data.quote_id.clone(),
|
||||
test_mode: data.test_mode,
|
||||
payment_method_balance: data.payment_method_balance.clone(),
|
||||
connector_http_status_code: data.connector_http_status_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -990,6 +992,7 @@ impl<F1, F2>
|
||||
quote_id: data.quote_id.clone(),
|
||||
test_mode: data.test_mode,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: data.connector_http_status_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,3 +365,45 @@ pub fn handle_json_response_deserialization_failure(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_http_status_code_type(
|
||||
status_code: u16,
|
||||
) -> CustomResult<String, errors::ApiErrorResponse> {
|
||||
let status_code_type = match status_code {
|
||||
100..=199 => "1xx",
|
||||
200..=299 => "2xx",
|
||||
300..=399 => "3xx",
|
||||
400..=499 => "4xx",
|
||||
500..=599 => "5xx",
|
||||
_ => Err(errors::ApiErrorResponse::InternalServerError)
|
||||
.into_report()
|
||||
.attach_printable("Invalid http status code")?,
|
||||
};
|
||||
Ok(status_code_type.to_string())
|
||||
}
|
||||
|
||||
pub fn add_connector_http_status_code_metrics(option_status_code: Option<u16>) {
|
||||
if let Some(status_code) = option_status_code {
|
||||
let status_code_type = get_http_status_code_type(status_code).ok();
|
||||
match status_code_type.as_deref() {
|
||||
Some("1xx") => {
|
||||
metrics::CONNECTOR_HTTP_STATUS_CODE_1XX_COUNT.add(&metrics::CONTEXT, 1, &[])
|
||||
}
|
||||
Some("2xx") => {
|
||||
metrics::CONNECTOR_HTTP_STATUS_CODE_2XX_COUNT.add(&metrics::CONTEXT, 1, &[])
|
||||
}
|
||||
Some("3xx") => {
|
||||
metrics::CONNECTOR_HTTP_STATUS_CODE_3XX_COUNT.add(&metrics::CONTEXT, 1, &[])
|
||||
}
|
||||
Some("4xx") => {
|
||||
metrics::CONNECTOR_HTTP_STATUS_CODE_4XX_COUNT.add(&metrics::CONTEXT, 1, &[])
|
||||
}
|
||||
Some("5xx") => {
|
||||
metrics::CONNECTOR_HTTP_STATUS_CODE_5XX_COUNT.add(&metrics::CONTEXT, 1, &[])
|
||||
}
|
||||
_ => logger::info!("Skip metrics as invalid http status code received from connector"),
|
||||
};
|
||||
} else {
|
||||
logger::info!("Skip metrics as no http status code received from connector")
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,6 +88,7 @@ fn construct_payment_router_data() -> types::PaymentsAuthorizeRouterData {
|
||||
quote_id: None,
|
||||
test_mode: None,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,6 +141,7 @@ fn construct_refund_router_data<F>() -> types::RefundsRouterData<F> {
|
||||
quote_id: None,
|
||||
test_mode: None,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -504,6 +504,7 @@ pub trait ConnectorActions: Connector {
|
||||
quote_id: None,
|
||||
test_mode: None,
|
||||
payment_method_balance: None,
|
||||
connector_http_status_code: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -352,7 +352,8 @@ async fn payments_create_core() {
|
||||
mandate_id: None,
|
||||
..Default::default()
|
||||
};
|
||||
let expected_response = services::ApplicationResponse::Json(expected_response);
|
||||
let expected_response =
|
||||
services::ApplicationResponse::JsonWithHeaders((expected_response, vec![]));
|
||||
let actual_response =
|
||||
payments::payments_core::<api::Authorize, api::PaymentsResponse, _, _, _>(
|
||||
&state,
|
||||
@ -498,7 +499,8 @@ async fn payments_create_core_adyen_no_redirect() {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let expected_response = services::ApplicationResponse::Json(api::PaymentsResponse {
|
||||
let expected_response = services::ApplicationResponse::JsonWithHeaders((
|
||||
api::PaymentsResponse {
|
||||
payment_id: Some(payment_id.clone()),
|
||||
status: api_enums::IntentStatus::Processing,
|
||||
amount: 6540,
|
||||
@ -512,7 +514,9 @@ async fn payments_create_core_adyen_no_redirect() {
|
||||
refunds: None,
|
||||
mandate_id: None,
|
||||
..Default::default()
|
||||
});
|
||||
},
|
||||
vec![],
|
||||
));
|
||||
let actual_response =
|
||||
payments::payments_core::<api::Authorize, api::PaymentsResponse, _, _, _>(
|
||||
&state,
|
||||
|
||||
@ -112,7 +112,8 @@ async fn payments_create_core() {
|
||||
mandate_id: None,
|
||||
..Default::default()
|
||||
};
|
||||
let expected_response = services::ApplicationResponse::Json(expected_response);
|
||||
let expected_response =
|
||||
services::ApplicationResponse::JsonWithHeaders((expected_response, vec![]));
|
||||
let actual_response =
|
||||
router::core::payments::payments_core::<api::Authorize, api::PaymentsResponse, _, _, _>(
|
||||
&state,
|
||||
@ -260,7 +261,8 @@ async fn payments_create_core_adyen_no_redirect() {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let expected_response = services::ApplicationResponse::Json(api::PaymentsResponse {
|
||||
let expected_response = services::ApplicationResponse::JsonWithHeaders((
|
||||
api::PaymentsResponse {
|
||||
payment_id: Some(payment_id.clone()),
|
||||
status: api_enums::IntentStatus::Processing,
|
||||
amount: 6540,
|
||||
@ -274,7 +276,9 @@ async fn payments_create_core_adyen_no_redirect() {
|
||||
refunds: None,
|
||||
mandate_id: None,
|
||||
..Default::default()
|
||||
});
|
||||
},
|
||||
vec![],
|
||||
));
|
||||
let actual_response =
|
||||
router::core::payments::payments_core::<api::Authorize, api::PaymentsResponse, _, _, _>(
|
||||
&state,
|
||||
|
||||
@ -54,7 +54,7 @@ async fn should_fail_recurring_payment_due_to_authentication(
|
||||
Event::Assert(Assert::IsPresent("man_")),// mandate id starting with man_
|
||||
Event::Trigger(Trigger::Click(By::Css("#pm-mandate-btn a"))),
|
||||
Event::Trigger(Trigger::Click(By::Id("card-submit-btn"))),
|
||||
Event::Assert(Assert::IsPresent("authentication_required: authentication_required")),
|
||||
Event::Assert(Assert::IsPresent("Your card was declined. This transaction requires authentication.")),
|
||||
]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user