mirror of
https://github.com/juspay/hyperswitch.git
synced 2025-10-29 00:49:42 +08:00
docs: standardise error types and error codes (#432)
This commit is contained in:
@ -325,7 +325,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
|
||||
errors::ApiErrorResponse::Unauthorized
|
||||
| errors::ApiErrorResponse::InvalidJwtToken
|
||||
| errors::ApiErrorResponse::GenericUnauthorized { .. }
|
||||
| errors::ApiErrorResponse::InvalidEphermeralKey => Self::Unauthorized,
|
||||
| errors::ApiErrorResponse::InvalidEphemeralKey => Self::Unauthorized,
|
||||
errors::ApiErrorResponse::InvalidRequestUrl
|
||||
| errors::ApiErrorResponse::InvalidHttpMethod => Self::InvalidRequestUrl,
|
||||
errors::ApiErrorResponse::MissingRequiredField { field_name } => {
|
||||
|
||||
@ -18,128 +18,67 @@ pub enum ErrorType {
|
||||
#[derive(Debug, Clone, router_derive::ApiError)]
|
||||
#[error(error_type_enum = ErrorType)]
|
||||
pub enum ApiErrorResponse {
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "IR_00", message = "{message:?}")]
|
||||
NotImplemented { message: NotImplementedMessage },
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_01",
|
||||
message = "API key not provided or invalid API key used. Provide API key in the Authorization header or create new API key, using api-key (e.g api-key: API_KEY)."
|
||||
message = "API key not provided or invalid API key used"
|
||||
)]
|
||||
Unauthorized,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_03", message = "Unrecognized request URL.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_02", message = "Unrecognized request URL")]
|
||||
InvalidRequestUrl,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_04", message = "The HTTP method is not applicable for this API.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_03", message = "The HTTP method is not applicable for this API")]
|
||||
InvalidHttpMethod,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_05", message = "Missing required param: {field_name}.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_04", message = "Missing required param: {field_name}")]
|
||||
MissingRequiredField { field_name: &'static str },
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_06",
|
||||
message = "{field_name} contains invalid data. Expected format is {expected_format}."
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_05",
|
||||
message = "{field_name} contains invalid data. Expected format is {expected_format}"
|
||||
)]
|
||||
InvalidDataFormat {
|
||||
field_name: String,
|
||||
expected_format: String,
|
||||
},
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "{message}")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_06", message = "{message}")]
|
||||
InvalidRequestData { message: String },
|
||||
/// Typically used when a field has invalid value, or deserialization of the value contained in
|
||||
/// a field fails.
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Invalid value provided: {field_name}.")]
|
||||
/// Typically used when a field has invalid value, or deserialization of the value contained in a field fails.
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Invalid value provided: {field_name}")]
|
||||
InvalidDataValue { field_name: &'static str },
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Client secret was not provided")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Client secret was not provided")]
|
||||
ClientSecretNotGiven,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "The client_secret provided does not match the client_secret associated with the Payment.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_09", message = "The client_secret provided does not match the client_secret associated with the Payment")]
|
||||
ClientSecretInvalid,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Customer has existing mandate/subsciption.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_10", message = "Customer has active mandate/subsciption")]
|
||||
MandateActive,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_07", message = "Customer has already redacted.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_11", message = "Customer has already been redacted")]
|
||||
CustomerRedacted,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Reached maximum refund attempts")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_12", message = "Reached maximum refund attempts")]
|
||||
MaximumRefundCount,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_08", message = "Refund amount exceeds the payment amount.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_13", message = "Refund amount exceeds the payment amount")]
|
||||
RefundAmountExceedsPaymentAmount,
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_09", message = "This PaymentIntent could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}.")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_14", message = "This Payment could not be {current_flow} because it has a {field_name} of {current_value}. The expected state is {states}")]
|
||||
PaymentUnexpectedState {
|
||||
current_flow: String,
|
||||
field_name: String,
|
||||
current_value: String,
|
||||
states: String,
|
||||
},
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_10", message = "Invalid Ephemeral Key for the customer")]
|
||||
InvalidEphermeralKey,
|
||||
/// Typically used when information involving multiple fields or previously provided
|
||||
/// information doesn't satisfy a condition.
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_10", message = "{message}")]
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_15", message = "Invalid Ephemeral Key for the customer")]
|
||||
InvalidEphemeralKey,
|
||||
/// Typically used when information involving multiple fields or previously provided information doesn't satisfy a condition.
|
||||
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_16", message = "{message}")]
|
||||
PreconditionFailed { message: String },
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_11",
|
||||
message = "Access forbidden, invalid JWT token was used."
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_17",
|
||||
message = "Access forbidden, invalid JWT token was used"
|
||||
)]
|
||||
InvalidJwtToken,
|
||||
#[error(
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_12",
|
||||
error_type = ErrorType::InvalidRequestError, code = "IR_18",
|
||||
message = "{message}",
|
||||
)]
|
||||
GenericUnauthorized { message: String },
|
||||
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_01", message = "Payment failed while processing with connector. Retry payment.")]
|
||||
PaymentAuthorizationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_02", message = "Payment failed while processing with connector. Retry payment.")]
|
||||
PaymentAuthenticationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_03", message = "Capture attempt failed while processing with connector.")]
|
||||
PaymentCaptureFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_04", message = "Capture attempt failed while processing with connector.")]
|
||||
InvalidCardData { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_05", message = "Payment failed while processing with connector. Retry payment.")]
|
||||
CardExpired { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_06", message = "Refund failed while processing with connector. Retry refund.")]
|
||||
RefundFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_01", message = "Verification failed while processing with connector. Retry operation.")]
|
||||
VerificationFailed { data: Option<serde_json::Value> },
|
||||
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "RE_00", message = "Something went wrong.")]
|
||||
InternalServerError,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_01", message = "Duplicate refund request. Refund already attempted with the refund ID.")]
|
||||
DuplicateRefundRequest,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Refund does not exist in our records.")]
|
||||
RefundNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Customer does not exist in our records.")]
|
||||
CustomerNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Payment does not exist in our records.")]
|
||||
PaymentNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Payment method does not exist in our records.")]
|
||||
PaymentMethodNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Merchant account does not exist in our records.")]
|
||||
MerchantAccountNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Merchant connector account does not exist in our records.")]
|
||||
MerchantConnectorAccountNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Resource ID does not exist in our records.")]
|
||||
ResourceIdNotFound,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_01", message = "Duplicate mandate request. Mandate already attempted with the Mandate ID.")]
|
||||
DuplicateMandate,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_02", message = "Mandate does not exist in our records.")]
|
||||
MandateNotFound,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "RE_03", message = "Return URL is not configured and not passed in payments request.")]
|
||||
ReturnUrlUnavailable,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "RE_03", message = "Refunds not possible through hyperswitch. Please raise Refunds through {connector} dashboard")]
|
||||
RefundNotPossible { connector: String },
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The merchant account with the specified details already exists in our records.")]
|
||||
DuplicateMerchantAccount,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The merchant connector account with the specified details already exists in our records.")]
|
||||
DuplicateMerchantConnectorAccount,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The payment method with the specified details already exists in our records.")]
|
||||
DuplicatePaymentMethod,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "RE_04", message = "The payment with the specified payment_id '{payment_id}' already exists in our records.")]
|
||||
DuplicatePayment { payment_id: String },
|
||||
#[error(error_type= ErrorType::InvalidRequestError, code = "RE_05", message = "The payment has not succeeded yet")]
|
||||
PaymentNotSucceeded,
|
||||
#[error(error_type= ErrorType::ObjectNotFound, code = "RE_05", message = "Successful payment not found for the given payment id")]
|
||||
SuccessfulPaymentNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_05", message = "The connector provided in the request is incorrect or not available")]
|
||||
IncorrectConnectorNameGiven,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "RE_05", message = "Address does not exist in our records.")]
|
||||
AddressNotFound,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "RE_03", message = "Mandate Validation Failed" )]
|
||||
MandateValidationFailed { reason: String },
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "IR_00", message = "{message:?}")]
|
||||
NotImplemented { message: NotImplementedMessage },
|
||||
#[error(error_type = ErrorType::ConnectorError, code = "CE_00", message = "{code}: {message}", ignore = "status_code")]
|
||||
ExternalConnectorError {
|
||||
code: String,
|
||||
@ -147,6 +86,65 @@ pub enum ApiErrorResponse {
|
||||
connector: String,
|
||||
status_code: u16,
|
||||
},
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_01", message = "Payment failed during authorization with connector. Retry payment")]
|
||||
PaymentAuthorizationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_02", message = "Payment failed during authentication with connector. Retry payment")]
|
||||
PaymentAuthenticationFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_03", message = "Capture attempt failed while processing with connector")]
|
||||
PaymentCaptureFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_04", message = "The card data is invalid")]
|
||||
InvalidCardData { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_05", message = "The card has expired")]
|
||||
CardExpired { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_06", message = "Refund failed while processing with connector. Retry refund")]
|
||||
RefundFailed { data: Option<serde_json::Value> },
|
||||
#[error(error_type = ErrorType::ProcessingError, code = "CE_07", message = "Verification failed while processing with connector. Retry operation")]
|
||||
VerificationFailed { data: Option<serde_json::Value> },
|
||||
|
||||
#[error(error_type = ErrorType::ServerNotAvailable, code = "HE_00", message = "Something went wrong")]
|
||||
InternalServerError,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "Duplicate refund request. Refund already attempted with the refund ID")]
|
||||
DuplicateRefundRequest,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "Duplicate mandate request. Mandate already attempted with the Mandate ID")]
|
||||
DuplicateMandate,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The merchant account with the specified details already exists in our records")]
|
||||
DuplicateMerchantAccount,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The merchant connector account with the specified details already exists in our records")]
|
||||
DuplicateMerchantConnectorAccount,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The payment method with the specified details already exists in our records")]
|
||||
DuplicatePaymentMethod,
|
||||
#[error(error_type = ErrorType::DuplicateRequest, code = "HE_01", message = "The payment with the specified payment_id '{payment_id}' already exists in our records")]
|
||||
DuplicatePayment { payment_id: String },
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Refund does not exist in our records")]
|
||||
RefundNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Customer does not exist in our records")]
|
||||
CustomerNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Payment does not exist in our records")]
|
||||
PaymentNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Payment method does not exist in our records")]
|
||||
PaymentMethodNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Merchant account does not exist in our records")]
|
||||
MerchantAccountNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Merchant connector account does not exist in our records")]
|
||||
MerchantConnectorAccountNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Resource ID does not exist in our records")]
|
||||
ResourceIdNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_02", message = "Mandate does not exist in our records")]
|
||||
MandateNotFound,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "Return URL is not configured and not passed in payments request")]
|
||||
ReturnUrlUnavailable,
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "This refund is not possible through Hyperswitch. Please raise the refund through {connector} dashboard")]
|
||||
RefundNotPossible { connector: String },
|
||||
#[error(error_type = ErrorType::ValidationError, code = "HE_03", message = "Mandate Validation Failed" )]
|
||||
MandateValidationFailed { reason: String },
|
||||
#[error(error_type= ErrorType::ValidationError, code = "HE_03", message = "The payment has not succeeded yet. Please pass a successful payment to initiate refund")]
|
||||
PaymentNotSucceeded,
|
||||
#[error(error_type= ErrorType::ObjectNotFound, code = "HE_04", message = "Successful payment not found for the given payment id")]
|
||||
SuccessfulPaymentNotFound,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "The connector provided in the request is incorrect or not available")]
|
||||
IncorrectConnectorNameGiven,
|
||||
#[error(error_type = ErrorType::ObjectNotFound, code = "HE_04", message = "Address does not exist in our records")]
|
||||
AddressNotFound,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@ -185,7 +183,7 @@ impl actix_web::ResponseError for ApiErrorResponse {
|
||||
|
||||
match self {
|
||||
Self::Unauthorized
|
||||
| Self::InvalidEphermeralKey
|
||||
| Self::InvalidEphemeralKey
|
||||
| Self::InvalidJwtToken
|
||||
| Self::GenericUnauthorized { .. } => StatusCode::UNAUTHORIZED, // 401
|
||||
Self::ExternalConnectorError { status_code, .. } => {
|
||||
|
||||
@ -236,7 +236,7 @@ pub async fn is_ephemeral_auth(
|
||||
.change_context(errors::ApiErrorResponse::Unauthorized)?;
|
||||
|
||||
if ephemeral_key.customer_id.ne(customer_id) {
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidEphermeralKey));
|
||||
return Err(report!(errors::ApiErrorResponse::InvalidEphemeralKey));
|
||||
}
|
||||
|
||||
Ok(Box::new(MerchantIdAuth(ephemeral_key.merchant_id)))
|
||||
|
||||
Reference in New Issue
Block a user