mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-11-01 02:57:02 +08:00
refactor(router): remove WebhookApiErrorSwitch and implement error mapping using ErrorSwitch (#1660)
Co-authored-by: Sanchith Hegde <sanchith.hegde@juspay.in>
This commit is contained in:
committed by
GitHub
parent
728177666b
commit
a7c66ddea2
@ -1,5 +1,6 @@
|
||||
pub mod api_error_response;
|
||||
pub mod error_handlers;
|
||||
pub mod transformers;
|
||||
pub mod utils;
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#![allow(dead_code, unused_variables)]
|
||||
|
||||
use api_models::errors::types::Extra;
|
||||
use http::StatusCode;
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize)]
|
||||
@ -261,244 +260,3 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
||||
}
|
||||
|
||||
impl crate::services::EmbedError for error_stack::Report<ApiErrorResponse> {}
|
||||
|
||||
impl common_utils::errors::ErrorSwitch<api_models::errors::types::ApiErrorResponse>
|
||||
for ApiErrorResponse
|
||||
{
|
||||
fn switch(&self) -> api_models::errors::types::ApiErrorResponse {
|
||||
use api_models::errors::types::{ApiError, ApiErrorResponse as AER};
|
||||
|
||||
let error_message = self.error_message();
|
||||
let error_codes = self.error_code();
|
||||
let error_type = self.error_type();
|
||||
|
||||
match self {
|
||||
Self::NotImplemented { message } => {
|
||||
AER::NotImplemented(ApiError::new("IR", 0, format!("{message:?}"), None))
|
||||
}
|
||||
Self::Unauthorized => AER::Unauthorized(ApiError::new(
|
||||
"IR",
|
||||
1,
|
||||
"API key not provided or invalid API key used", None
|
||||
)),
|
||||
Self::InvalidRequestUrl => {
|
||||
AER::NotFound(ApiError::new("IR", 2, "Unrecognized request URL", None))
|
||||
}
|
||||
Self::InvalidHttpMethod => AER::MethodNotAllowed(ApiError::new(
|
||||
"IR",
|
||||
3,
|
||||
"The HTTP method is not applicable for this API", None
|
||||
)),
|
||||
Self::MissingRequiredField { field_name } => AER::BadRequest(
|
||||
ApiError::new("IR", 4, format!("Missing required param: {field_name}"), None),
|
||||
),
|
||||
Self::InvalidDataFormat {
|
||||
field_name,
|
||||
expected_format,
|
||||
} => AER::Unprocessable(ApiError::new(
|
||||
"IR",
|
||||
5,
|
||||
format!(
|
||||
"{field_name} contains invalid data. Expected format is {expected_format}"
|
||||
), None
|
||||
)),
|
||||
Self::InvalidRequestData { message } => {
|
||||
AER::Unprocessable(ApiError::new("IR", 6, message.to_string(), None))
|
||||
}
|
||||
Self::InvalidDataValue { field_name } => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
7,
|
||||
format!("Invalid value provided: {field_name}"), None
|
||||
)),
|
||||
Self::ClientSecretNotGiven => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
8,
|
||||
"client_secret was not provided", None
|
||||
)),
|
||||
Self::ClientSecretInvalid => {
|
||||
AER::BadRequest(ApiError::new("IR", 9, "The client_secret provided does not match the client_secret associated with the Payment", None))
|
||||
}
|
||||
Self::MandateActive => {
|
||||
AER::BadRequest(ApiError::new("IR", 10, "Customer has active mandate/subsciption", None))
|
||||
}
|
||||
Self::CustomerRedacted => {
|
||||
AER::BadRequest(ApiError::new("IR", 11, "Customer has already been redacted", None))
|
||||
}
|
||||
Self::MaximumRefundCount => AER::BadRequest(ApiError::new("IR", 12, "Reached maximum refund attempts", None)),
|
||||
Self::RefundAmountExceedsPaymentAmount => {
|
||||
AER::BadRequest(ApiError::new("IR", 13, "Refund amount exceeds the payment amount", None))
|
||||
}
|
||||
Self::PaymentUnexpectedState {
|
||||
current_flow,
|
||||
field_name,
|
||||
current_value,
|
||||
states,
|
||||
} => AER::BadRequest(ApiError::new("IR", 14, format!("This Payment could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}"), None)),
|
||||
Self::InvalidEphemeralKey => AER::Unauthorized(ApiError::new("IR", 15, "Invalid Ephemeral Key for the customer", None)),
|
||||
Self::PreconditionFailed { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 16, message.to_string(), None))
|
||||
}
|
||||
Self::InvalidJwtToken => AER::Unauthorized(ApiError::new("IR", 17, "Access forbidden, invalid JWT token was used", None)),
|
||||
Self::GenericUnauthorized { message } => {
|
||||
AER::Unauthorized(ApiError::new("IR", 18, message.to_string(), None))
|
||||
},
|
||||
Self::ClientSecretExpired => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
19,
|
||||
"The provided client_secret has expired", None
|
||||
)),
|
||||
Self::MissingRequiredFields { field_names } => AER::BadRequest(
|
||||
ApiError::new("IR", 21, "Missing required params".to_string(), Some(Extra {data: Some(serde_json::json!(field_names)), ..Default::default() })),
|
||||
),
|
||||
Self::AccessForbidden => AER::ForbiddenCommonResource(ApiError::new("IR", 22, "Access forbidden. Not authorized to access this resource", None)),
|
||||
Self::FileProviderNotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 23, message.to_string(), None))
|
||||
},
|
||||
Self::UnprocessableEntity {entity} => AER::Unprocessable(ApiError::new("IR", 23, format!("{entity} expired or invalid"), None)),
|
||||
Self::ExternalConnectorError {
|
||||
code,
|
||||
message,
|
||||
connector,
|
||||
reason,
|
||||
status_code,
|
||||
} => AER::ConnectorError(ApiError::new("CE", 0, format!("{code}: {message}"), Some(Extra {connector: Some(connector.clone()), reason: reason.clone(), ..Default::default()})), StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)),
|
||||
Self::PaymentAuthorizationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Payment failed during authorization with connector. Retry payment", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::PaymentAuthenticationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 2, "Payment failed during authentication with connector. Retry payment", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::PaymentCaptureFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 3, "Capture attempt failed while processing with connector", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::DisputeFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Dispute operation failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::InvalidCardData { data } => AER::BadRequest(ApiError::new("CE", 4, "The card data is invalid", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::CardExpired { data } => AER::BadRequest(ApiError::new("CE", 5, "The card has expired", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::RefundFailed { data } => AER::BadRequest(ApiError::new("CE", 6, "Refund failed while processing with connector. Retry refund", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::VerificationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 7, "Verification failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
},
|
||||
Self::MandateUpdateFailed | Self::MandateSerializationFailed | Self::MandateDeserializationFailed | Self::InternalServerError => {
|
||||
AER::InternalServerError(ApiError::new("HE", 0, "Something went wrong", None))
|
||||
}
|
||||
Self::DuplicateRefundRequest => AER::BadRequest(ApiError::new("HE", 1, "Duplicate refund request. Refund already attempted with the refund ID", None)),
|
||||
Self::DuplicateMandate => AER::BadRequest(ApiError::new("HE", 1, "Duplicate mandate request. Mandate already attempted with the Mandate ID", None)),
|
||||
Self::DuplicateMerchantAccount => AER::BadRequest(ApiError::new("HE", 1, "The merchant account with the specified details already exists in our records", None)),
|
||||
Self::DuplicateMerchantConnectorAccount { connector_label } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, format!("The merchant connector account with the specified connector_label '{connector_label}' already exists in our records"), None))
|
||||
}
|
||||
Self::DuplicatePaymentMethod => AER::BadRequest(ApiError::new("HE", 1, "The payment method with the specified details already exists in our records", None)),
|
||||
Self::DuplicatePayment { payment_id } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, format!("The payment with the specified payment_id '{payment_id}' already exists in our records"), None))
|
||||
}
|
||||
Self::RefundNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Refund does not exist in our records.", None))
|
||||
}
|
||||
Self::CustomerNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Customer does not exist in our records", None))
|
||||
}
|
||||
Self::ConfigNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Config key does not exist in our records.", None))
|
||||
}
|
||||
Self::PaymentNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment does not exist in our records", None))
|
||||
}
|
||||
Self::PaymentMethodNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment method does not exist in our records", None))
|
||||
}
|
||||
Self::MerchantAccountNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Merchant account does not exist in our records", None))
|
||||
}
|
||||
Self::MerchantConnectorAccountNotFound { id } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, format!("Merchant connector account with id '{id}' does not exist in our records"), None))
|
||||
}
|
||||
Self::MerchantConnectorAccountDisabled => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "The selected merchant connector account is disabled", None))
|
||||
}
|
||||
Self::ResourceIdNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Resource ID does not exist in our records", None))
|
||||
}
|
||||
Self::MandateNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Mandate does not exist in our records", None))
|
||||
}
|
||||
Self::ReturnUrlUnavailable => AER::NotFound(ApiError::new("HE", 3, "Return URL is not configured and not passed in payments request", None)),
|
||||
Self::RefundNotPossible { connector } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, format!("This refund is not possible through Hyperswitch. Please raise the refund through {connector} dashboard"), None))
|
||||
}
|
||||
Self::MandateValidationFailed { reason } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "Mandate Validation Failed", Some(Extra { reason: Some(reason.clone()), ..Default::default() })))
|
||||
}
|
||||
Self::PaymentNotSucceeded => AER::BadRequest(ApiError::new("HE", 3, "The payment has not succeeded yet. Please pass a successful payment to initiate refund", None)),
|
||||
Self::SuccessfulPaymentNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "Successful payment not found for the given payment id", None))
|
||||
}
|
||||
Self::IncorrectConnectorNameGiven => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "The connector provided in the request is incorrect or not available", None))
|
||||
}
|
||||
Self::AddressNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "Address does not exist in our records", None))
|
||||
},
|
||||
Self::GenericNotFoundError { message } => {
|
||||
AER::NotFound(ApiError::new("HE", 5, message, None))
|
||||
},
|
||||
Self::ApiKeyNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "API Key does not exist in our records", None))
|
||||
}
|
||||
Self::NotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "Payment method type not supported", Some(Extra {reason: Some(message.to_owned()), ..Default::default()})))
|
||||
},
|
||||
Self::InvalidCardIin => AER::BadRequest(ApiError::new("HE", 3, "The provided card IIN does not exist", None)),
|
||||
Self::InvalidCardIinLength => AER::BadRequest(ApiError::new("HE", 3, "The provided card IIN length is invalid, please provide an IIN with 6 digits", None)),
|
||||
Self::FlowNotSupported { flow, connector } => {
|
||||
AER::BadRequest(ApiError::new("IR", 20, format!("{flow} flow not supported"), Some(Extra {connector: Some(connector.to_owned()), ..Default::default()}))) //FIXME: error message
|
||||
}
|
||||
Self::DisputeNotFound { .. } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Dispute does not exist in our records", None))
|
||||
}
|
||||
Self::FileNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File does not exist in our records", None))
|
||||
}
|
||||
Self::FileNotAvailable => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File not available", None))
|
||||
}
|
||||
Self::DisputeStatusValidationFailed { .. } => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "Dispute status validation failed", None))
|
||||
}
|
||||
Self::FileValidationFailed { reason } => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, format!("File validation failed {reason}"), None))
|
||||
}
|
||||
Self::MissingFile => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File not found in the request", None))
|
||||
}
|
||||
Self::MissingFilePurpose => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File purpose not found in the request or is invalid", None))
|
||||
}
|
||||
Self::MissingFileContentType => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File content type not found", None))
|
||||
}
|
||||
Self::MissingDisputeId => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "Dispute id not found in the request", None))
|
||||
}
|
||||
Self::WebhookAuthenticationFailed => {
|
||||
AER::Unauthorized(ApiError::new("WE", 1, "Webhook authentication failed", None))
|
||||
}
|
||||
Self::WebhookResourceNotFound => {
|
||||
AER::NotFound(ApiError::new("WE", 4, "Webhook resource was not found", None))
|
||||
}
|
||||
Self::WebhookBadRequest => {
|
||||
AER::BadRequest(ApiError::new("WE", 2, "Bad request body received", None))
|
||||
}
|
||||
Self::WebhookProcessingFailure => {
|
||||
AER::InternalServerError(ApiError::new("WE", 3, "There was an issue processing the webhook", None))
|
||||
},
|
||||
Self::IncorrectPaymentMethodConfiguration => {
|
||||
AER::BadRequest(ApiError::new("HE", 4, "No eligible connector was found for the current payment method configuration", None))
|
||||
}
|
||||
Self::WebhookUnprocessableEntity => {
|
||||
AER::Unprocessable(ApiError::new("WE", 5, "There was an issue processing the webhook body", None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
255
crates/router/src/core/errors/transformers.rs
Normal file
255
crates/router/src/core/errors/transformers.rs
Normal file
@ -0,0 +1,255 @@
|
||||
use api_models::errors::types::Extra;
|
||||
use common_utils::errors::ErrorSwitch;
|
||||
use http::StatusCode;
|
||||
|
||||
use super::{ApiErrorResponse, ConnectorError};
|
||||
|
||||
impl ErrorSwitch<api_models::errors::types::ApiErrorResponse> for ApiErrorResponse {
|
||||
fn switch(&self) -> api_models::errors::types::ApiErrorResponse {
|
||||
use api_models::errors::types::{ApiError, ApiErrorResponse as AER};
|
||||
|
||||
match self {
|
||||
Self::NotImplemented { message } => {
|
||||
AER::NotImplemented(ApiError::new("IR", 0, format!("{message:?}"), None))
|
||||
}
|
||||
Self::Unauthorized => AER::Unauthorized(ApiError::new(
|
||||
"IR",
|
||||
1,
|
||||
"API key not provided or invalid API key used", None
|
||||
)),
|
||||
Self::InvalidRequestUrl => {
|
||||
AER::NotFound(ApiError::new("IR", 2, "Unrecognized request URL", None))
|
||||
}
|
||||
Self::InvalidHttpMethod => AER::MethodNotAllowed(ApiError::new(
|
||||
"IR",
|
||||
3,
|
||||
"The HTTP method is not applicable for this API", None
|
||||
)),
|
||||
Self::MissingRequiredField { field_name } => AER::BadRequest(
|
||||
ApiError::new("IR", 4, format!("Missing required param: {field_name}"), None),
|
||||
),
|
||||
Self::InvalidDataFormat {
|
||||
field_name,
|
||||
expected_format,
|
||||
} => AER::Unprocessable(ApiError::new(
|
||||
"IR",
|
||||
5,
|
||||
format!(
|
||||
"{field_name} contains invalid data. Expected format is {expected_format}"
|
||||
), None
|
||||
)),
|
||||
Self::InvalidRequestData { message } => {
|
||||
AER::Unprocessable(ApiError::new("IR", 6, message.to_string(), None))
|
||||
}
|
||||
Self::InvalidDataValue { field_name } => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
7,
|
||||
format!("Invalid value provided: {field_name}"), None
|
||||
)),
|
||||
Self::ClientSecretNotGiven => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
8,
|
||||
"client_secret was not provided", None
|
||||
)),
|
||||
Self::ClientSecretInvalid => {
|
||||
AER::BadRequest(ApiError::new("IR", 9, "The client_secret provided does not match the client_secret associated with the Payment", None))
|
||||
}
|
||||
Self::MandateActive => {
|
||||
AER::BadRequest(ApiError::new("IR", 10, "Customer has active mandate/subsciption", None))
|
||||
}
|
||||
Self::CustomerRedacted => {
|
||||
AER::BadRequest(ApiError::new("IR", 11, "Customer has already been redacted", None))
|
||||
}
|
||||
Self::MaximumRefundCount => AER::BadRequest(ApiError::new("IR", 12, "Reached maximum refund attempts", None)),
|
||||
Self::RefundAmountExceedsPaymentAmount => {
|
||||
AER::BadRequest(ApiError::new("IR", 13, "Refund amount exceeds the payment amount", None))
|
||||
}
|
||||
Self::PaymentUnexpectedState {
|
||||
current_flow,
|
||||
field_name,
|
||||
current_value,
|
||||
states,
|
||||
} => AER::BadRequest(ApiError::new("IR", 14, format!("This Payment could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}"), None)),
|
||||
Self::InvalidEphemeralKey => AER::Unauthorized(ApiError::new("IR", 15, "Invalid Ephemeral Key for the customer", None)),
|
||||
Self::PreconditionFailed { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 16, message.to_string(), None))
|
||||
}
|
||||
Self::InvalidJwtToken => AER::Unauthorized(ApiError::new("IR", 17, "Access forbidden, invalid JWT token was used", None)),
|
||||
Self::GenericUnauthorized { message } => {
|
||||
AER::Unauthorized(ApiError::new("IR", 18, message.to_string(), None))
|
||||
},
|
||||
Self::ClientSecretExpired => AER::BadRequest(ApiError::new(
|
||||
"IR",
|
||||
19,
|
||||
"The provided client_secret has expired", None
|
||||
)),
|
||||
Self::MissingRequiredFields { field_names } => AER::BadRequest(
|
||||
ApiError::new("IR", 21, "Missing required params".to_string(), Some(Extra {data: Some(serde_json::json!(field_names)), ..Default::default() })),
|
||||
),
|
||||
Self::AccessForbidden => AER::ForbiddenCommonResource(ApiError::new("IR", 22, "Access forbidden. Not authorized to access this resource", None)),
|
||||
Self::FileProviderNotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("IR", 23, message.to_string(), None))
|
||||
},
|
||||
Self::UnprocessableEntity {entity} => AER::Unprocessable(ApiError::new("IR", 23, format!("{entity} expired or invalid"), None)),
|
||||
Self::ExternalConnectorError {
|
||||
code,
|
||||
message,
|
||||
connector,
|
||||
reason,
|
||||
status_code,
|
||||
} => AER::ConnectorError(ApiError::new("CE", 0, format!("{code}: {message}"), Some(Extra {connector: Some(connector.clone()), reason: reason.clone(), ..Default::default()})), StatusCode::from_u16(*status_code).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)),
|
||||
Self::PaymentAuthorizationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Payment failed during authorization with connector. Retry payment", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::PaymentAuthenticationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 2, "Payment failed during authentication with connector. Retry payment", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::PaymentCaptureFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 3, "Capture attempt failed while processing with connector", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::DisputeFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 1, "Dispute operation failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
}
|
||||
Self::InvalidCardData { data } => AER::BadRequest(ApiError::new("CE", 4, "The card data is invalid", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::CardExpired { data } => AER::BadRequest(ApiError::new("CE", 5, "The card has expired", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::RefundFailed { data } => AER::BadRequest(ApiError::new("CE", 6, "Refund failed while processing with connector. Retry refund", Some(Extra { data: data.clone(), ..Default::default()}))),
|
||||
Self::VerificationFailed { data } => {
|
||||
AER::BadRequest(ApiError::new("CE", 7, "Verification failed while processing with connector. Retry operation", Some(Extra { data: data.clone(), ..Default::default()})))
|
||||
},
|
||||
Self::MandateUpdateFailed | Self::MandateSerializationFailed | Self::MandateDeserializationFailed | Self::InternalServerError => {
|
||||
AER::InternalServerError(ApiError::new("HE", 0, "Something went wrong", None))
|
||||
}
|
||||
Self::DuplicateRefundRequest => AER::BadRequest(ApiError::new("HE", 1, "Duplicate refund request. Refund already attempted with the refund ID", None)),
|
||||
Self::DuplicateMandate => AER::BadRequest(ApiError::new("HE", 1, "Duplicate mandate request. Mandate already attempted with the Mandate ID", None)),
|
||||
Self::DuplicateMerchantAccount => AER::BadRequest(ApiError::new("HE", 1, "The merchant account with the specified details already exists in our records", None)),
|
||||
Self::DuplicateMerchantConnectorAccount { connector_label } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, format!("The merchant connector account with the specified connector_label '{connector_label}' already exists in our records"), None))
|
||||
}
|
||||
Self::DuplicatePaymentMethod => AER::BadRequest(ApiError::new("HE", 1, "The payment method with the specified details already exists in our records", None)),
|
||||
Self::DuplicatePayment { payment_id } => {
|
||||
AER::BadRequest(ApiError::new("HE", 1, format!("The payment with the specified payment_id '{payment_id}' already exists in our records"), None))
|
||||
}
|
||||
Self::RefundNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Refund does not exist in our records.", None))
|
||||
}
|
||||
Self::CustomerNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Customer does not exist in our records", None))
|
||||
}
|
||||
Self::ConfigNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Config key does not exist in our records.", None))
|
||||
}
|
||||
Self::PaymentNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment does not exist in our records", None))
|
||||
}
|
||||
Self::PaymentMethodNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Payment method does not exist in our records", None))
|
||||
}
|
||||
Self::MerchantAccountNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Merchant account does not exist in our records", None))
|
||||
}
|
||||
Self::MerchantConnectorAccountNotFound { id } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, format!("Merchant connector account with id '{id}' does not exist in our records"), None))
|
||||
}
|
||||
Self::MerchantConnectorAccountDisabled => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "The selected merchant connector account is disabled", None))
|
||||
}
|
||||
Self::ResourceIdNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Resource ID does not exist in our records", None))
|
||||
}
|
||||
Self::MandateNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Mandate does not exist in our records", None))
|
||||
}
|
||||
Self::ReturnUrlUnavailable => AER::NotFound(ApiError::new("HE", 3, "Return URL is not configured and not passed in payments request", None)),
|
||||
Self::RefundNotPossible { connector } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, format!("This refund is not possible through Hyperswitch. Please raise the refund through {connector} dashboard"), None))
|
||||
}
|
||||
Self::MandateValidationFailed { reason } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "Mandate Validation Failed", Some(Extra { reason: Some(reason.clone()), ..Default::default() })))
|
||||
}
|
||||
Self::PaymentNotSucceeded => AER::BadRequest(ApiError::new("HE", 3, "The payment has not succeeded yet. Please pass a successful payment to initiate refund", None)),
|
||||
Self::SuccessfulPaymentNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "Successful payment not found for the given payment id", None))
|
||||
}
|
||||
Self::IncorrectConnectorNameGiven => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "The connector provided in the request is incorrect or not available", None))
|
||||
}
|
||||
Self::AddressNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 4, "Address does not exist in our records", None))
|
||||
},
|
||||
Self::GenericNotFoundError { message } => {
|
||||
AER::NotFound(ApiError::new("HE", 5, message, None))
|
||||
},
|
||||
Self::ApiKeyNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "API Key does not exist in our records", None))
|
||||
}
|
||||
Self::NotSupported { message } => {
|
||||
AER::BadRequest(ApiError::new("HE", 3, "Payment method type not supported", Some(Extra {reason: Some(message.to_owned()), ..Default::default()})))
|
||||
},
|
||||
Self::InvalidCardIin => AER::BadRequest(ApiError::new("HE", 3, "The provided card IIN does not exist", None)),
|
||||
Self::InvalidCardIinLength => AER::BadRequest(ApiError::new("HE", 3, "The provided card IIN length is invalid, please provide an IIN with 6 digits", None)),
|
||||
Self::FlowNotSupported { flow, connector } => {
|
||||
AER::BadRequest(ApiError::new("IR", 20, format!("{flow} flow not supported"), Some(Extra {connector: Some(connector.to_owned()), ..Default::default()}))) //FIXME: error message
|
||||
}
|
||||
Self::DisputeNotFound { .. } => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "Dispute does not exist in our records", None))
|
||||
}
|
||||
Self::FileNotFound => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File does not exist in our records", None))
|
||||
}
|
||||
Self::FileNotAvailable => {
|
||||
AER::NotFound(ApiError::new("HE", 2, "File not available", None))
|
||||
}
|
||||
Self::DisputeStatusValidationFailed { .. } => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "Dispute status validation failed", None))
|
||||
}
|
||||
Self::FileValidationFailed { reason } => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, format!("File validation failed {reason}"), None))
|
||||
}
|
||||
Self::MissingFile => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File not found in the request", None))
|
||||
}
|
||||
Self::MissingFilePurpose => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File purpose not found in the request or is invalid", None))
|
||||
}
|
||||
Self::MissingFileContentType => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "File content type not found", None))
|
||||
}
|
||||
Self::MissingDisputeId => {
|
||||
AER::BadRequest(ApiError::new("HE", 2, "Dispute id not found in the request", None))
|
||||
}
|
||||
Self::WebhookAuthenticationFailed => {
|
||||
AER::Unauthorized(ApiError::new("WE", 1, "Webhook authentication failed", None))
|
||||
}
|
||||
Self::WebhookResourceNotFound => {
|
||||
AER::NotFound(ApiError::new("WE", 4, "Webhook resource was not found", None))
|
||||
}
|
||||
Self::WebhookBadRequest => {
|
||||
AER::BadRequest(ApiError::new("WE", 2, "Bad request body received", None))
|
||||
}
|
||||
Self::WebhookProcessingFailure => {
|
||||
AER::InternalServerError(ApiError::new("WE", 3, "There was an issue processing the webhook", None))
|
||||
},
|
||||
Self::IncorrectPaymentMethodConfiguration => {
|
||||
AER::BadRequest(ApiError::new("HE", 4, "No eligible connector was found for the current payment method configuration", None))
|
||||
}
|
||||
Self::WebhookUnprocessableEntity => {
|
||||
AER::Unprocessable(ApiError::new("WE", 5, "There was an issue processing the webhook body", None))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ErrorSwitch<ApiErrorResponse> for ConnectorError {
|
||||
fn switch(&self) -> ApiErrorResponse {
|
||||
match self {
|
||||
Self::WebhookSourceVerificationFailed => ApiErrorResponse::WebhookAuthenticationFailed,
|
||||
Self::WebhookSignatureNotFound
|
||||
| Self::WebhookReferenceIdNotFound
|
||||
| Self::WebhookResourceObjectNotFound
|
||||
| Self::WebhookBodyDecodingFailed
|
||||
| Self::WebhooksNotImplemented => ApiErrorResponse::WebhookBadRequest,
|
||||
Self::WebhookEventTypeNotFound => ApiErrorResponse::WebhookUnprocessableEntity,
|
||||
_ => ApiErrorResponse::InternalServerError,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,10 +1,10 @@
|
||||
pub mod types;
|
||||
pub mod utils;
|
||||
|
||||
use common_utils::errors::ReportSwitchExt;
|
||||
use error_stack::{report, IntoReport, ResultExt};
|
||||
use masking::ExposeInterface;
|
||||
use router_env::{instrument, tracing};
|
||||
use utils::WebhookApiErrorSwitch;
|
||||
|
||||
use super::{errors::StorageErrorExt, metrics};
|
||||
use crate::{
|
||||
|
||||
@ -1,7 +1,4 @@
|
||||
use error_stack::ResultExt;
|
||||
|
||||
use crate::{
|
||||
core::errors,
|
||||
db::{get_and_deserialize_key, StorageInterface},
|
||||
types::api,
|
||||
};
|
||||
@ -48,34 +45,3 @@ pub async fn lookup_webhook_event(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WebhookApiErrorSwitch<T> {
|
||||
fn switch(self) -> errors::RouterResult<T>;
|
||||
}
|
||||
|
||||
impl<T> WebhookApiErrorSwitch<T> for errors::CustomResult<T, errors::ConnectorError> {
|
||||
fn switch(self) -> errors::RouterResult<T> {
|
||||
match self {
|
||||
Ok(res) => Ok(res),
|
||||
Err(e) => match e.current_context() {
|
||||
errors::ConnectorError::WebhookSourceVerificationFailed => {
|
||||
Err(e).change_context(errors::ApiErrorResponse::WebhookAuthenticationFailed)
|
||||
}
|
||||
|
||||
errors::ConnectorError::WebhookSignatureNotFound
|
||||
| errors::ConnectorError::WebhookReferenceIdNotFound
|
||||
| errors::ConnectorError::WebhookResourceObjectNotFound
|
||||
| errors::ConnectorError::WebhookBodyDecodingFailed
|
||||
| errors::ConnectorError::WebhooksNotImplemented => {
|
||||
Err(e).change_context(errors::ApiErrorResponse::WebhookBadRequest)
|
||||
}
|
||||
|
||||
errors::ConnectorError::WebhookEventTypeNotFound => {
|
||||
Err(e).change_context(errors::ApiErrorResponse::WebhookUnprocessableEntity)
|
||||
}
|
||||
|
||||
_ => Err(e).change_context(errors::ApiErrorResponse::InternalServerError),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user