docs: standardise error types and error codes (#432)

This commit is contained in:
bernard-eugine
2023-01-31 16:46:51 +05:30
committed by GitHub
parent 010aff5f4c
commit 3dfd548cb8
4 changed files with 88 additions and 90 deletions

View File

@ -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 } => {

View File

@ -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, .. } => {

View File

@ -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)))