refactor(errors): error enums to use 'static str (#472)

This commit is contained in:
Narayan Bhat
2023-01-30 18:57:05 +05:30
committed by GitHub
parent fa7d087c0d
commit 24351a6c85
25 changed files with 84 additions and 79 deletions

View File

@ -20,7 +20,10 @@ pub enum StripeErrorCode {
InvalidRequestUrl,
#[error(error_type = StripeErrorType::InvalidRequestError, code = "parameter_missing", message = "Missing required param: {field_name}.")]
ParameterMissing { field_name: String, param: String },
ParameterMissing {
field_name: &'static str,
param: &'static str,
},
#[error(
error_type = StripeErrorType::InvalidRequestError, code = "parameter_unknown",
@ -327,7 +330,7 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
| errors::ApiErrorResponse::InvalidHttpMethod => Self::InvalidRequestUrl,
errors::ApiErrorResponse::MissingRequiredField { field_name } => {
Self::ParameterMissing {
field_name: field_name.to_owned(),
field_name,
param: field_name,
}
}
@ -395,8 +398,8 @@ impl From<errors::ApiErrorResponse> for StripeErrorCode {
Self::PreconditionFailed { message }
}
errors::ApiErrorResponse::InvalidDataValue { field_name } => Self::ParameterMissing {
field_name: field_name.to_owned(),
param: field_name.to_owned(),
field_name,
param: field_name,
},
errors::ApiErrorResponse::MaximumRefundCount => Self::MaximumRefundCount,
errors::ApiErrorResponse::PaymentNotSucceeded => Self::PaymentFailed,

View File

@ -383,7 +383,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest {
}
},
_ => Err(errors::ConnectorError::MissingRequiredField {
field_name: "payment_method".to_string(),
field_name: "payment_method",
}),
}?;
@ -411,7 +411,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for AdyenPaymentRequest {
reference,
return_url: item.router_return_url.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "router_return_url".into(),
field_name: "router_return_url",
},
)?,
shopper_interaction,

View File

@ -316,7 +316,7 @@ impl<F, T>
})
.transpose()
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "connector_metadata".to_string(),
field_name: "connector_metadata",
})?;
Ok(Self {
@ -372,7 +372,7 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for CreateRefundRequest {
.as_ref()
.get_required_value("connector_metadata")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "connector_metadata".to_string(),
field_name: "connector_metadata",
})?
.clone();
@ -384,7 +384,7 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for CreateRefundRequest {
payment: payment_details
.parse_value("PaymentDetails")
.change_context(errors::ConnectorError::MissingRequiredField {
field_name: "payment_details".to_string(),
field_name: "payment_details",
})?,
currency_code: item.request.currency.to_string(),
reference_transaction_id: item.request.connector_transaction_id.clone(),

View File

@ -55,7 +55,7 @@ impl TryFrom<&types::PaymentsSessionRouterData> for KlarnaSessionRequest {
}],
}),
None => Err(report!(errors::ConnectorError::MissingRequiredField {
field_name: "product_name".to_string()
field_name: "product_name",
})),
}
}
@ -98,7 +98,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for KlarnaPaymentsRequest {
}],
}),
None => Err(report!(errors::ConnectorError::MissingRequiredField {
field_name: "product_name".to_string()
field_name: "product_name"
})),
}
}

View File

@ -119,13 +119,13 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest {
}?;
let browser_info = item.request.browser_info.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "browser_info".to_string(),
field_name: "browser_info",
},
)?;
Ok(Self {
customer_ip: browser_info.ip_address.ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "browser_info.ip_address".to_string(),
field_name: "browser_info.ip_address",
},
)?,
merchant_pos_id: auth_type.merchant_pos_id,
@ -133,7 +133,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest {
currency_code: item.request.currency,
description: item.description.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "item.description".to_string(),
field_name: "item.description",
},
)?,
pay_methods: payment_method,
@ -501,7 +501,7 @@ impl<F> TryFrom<&types::RefundsRouterData<F>> for PayuRefundRequest {
refund: PayuRefundRequestData {
description: item.request.reason.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "item.request.reason".to_string(),
field_name: "item.request.reason",
},
)?,
amount: None,

View File

@ -167,25 +167,25 @@ fn validate_shipping_address_against_payment_method(
{
fp_utils::when(shipping_address.name.is_none(), || {
Err(errors::ConnectorError::MissingRequiredField {
field_name: "shipping.first_name".to_string(),
field_name: "shipping.first_name",
})
})?;
fp_utils::when(shipping_address.line1.is_none(), || {
Err(errors::ConnectorError::MissingRequiredField {
field_name: "shipping.line1".to_string(),
field_name: "shipping.line1",
})
})?;
fp_utils::when(shipping_address.country.is_none(), || {
Err(errors::ConnectorError::MissingRequiredField {
field_name: "shipping.country".to_string(),
field_name: "shipping.country",
})
})?;
fp_utils::when(shipping_address.zip.is_none(), || {
Err(errors::ConnectorError::MissingRequiredField {
field_name: "shipping.zip".to_string(),
field_name: "shipping.zip",
})
})?;
}

View File

@ -7,11 +7,11 @@ use crate::{
};
pub fn missing_field_err(
message: &str,
message: &'static str,
) -> Box<dyn Fn() -> error_stack::Report<errors::ConnectorError> + '_> {
Box::new(|| {
Box::new(move || {
errors::ConnectorError::MissingRequiredField {
field_name: message.to_string(),
field_name: message,
}
.into()
})

View File

@ -211,7 +211,7 @@ fn build_customer_info(
) -> Result<Customer, error_stack::Report<errors::ConnectorError>> {
let (billing, address) =
get_address(payment_address).ok_or(errors::ConnectorError::MissingRequiredField {
field_name: "billing.address.country".into(),
field_name: "billing.address.country",
})?;
let number_with_country_code = billing.phone.as_ref().and_then(|phone| {

View File

@ -87,7 +87,7 @@ where
.map(transform_fn);
reference_id.ok_or_else(|| {
errors::ConnectorError::MissingRequiredField {
field_name: "links.events".to_string(),
field_name: "links.events",
}
.into()
})

View File

@ -93,7 +93,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for WorldpayPaymentsRequest {
},
transaction_reference: item.attempt_id.clone().ok_or(
errors::ConnectorError::MissingRequiredField {
field_name: "attempt_id".to_string(),
field_name: "attempt_id",
},
)?,
channel: None,
@ -160,7 +160,7 @@ impl TryFrom<types::PaymentsResponseRouterData<WorldpayPaymentsResponse>>
status: match item.response.outcome {
Some(outcome) => enums::AttemptStatus::from(outcome),
None => Err(errors::ConnectorError::MissingRequiredField {
field_name: "outcome".to_string(),
field_name: "outcome",
})?,
},
description: item.response.description,

View File

@ -54,8 +54,11 @@ pub enum StorageError {
DatabaseError(error_stack::Report<storage_errors::DatabaseError>),
#[error("ValueNotFound: {0}")]
ValueNotFound(String),
#[error("DuplicateValue: {0}")]
DuplicateValue(String),
#[error("DuplicateValue: {entity} already exists {key:?}")]
DuplicateValue {
entity: &'static str,
key: Option<String>,
},
#[error("KV error")]
KVError,
#[error("Serialization failure")]
@ -224,7 +227,7 @@ pub enum ConnectorError {
#[error("Failed to handle connector response")]
ResponseHandlingFailed,
#[error("Missing required field: {field_name}")]
MissingRequiredField { field_name: String },
MissingRequiredField { field_name: &'static str },
#[error("Failed to obtain authentication type")]
FailedToObtainAuthType,
#[error("Failed to obtain certificate")]
@ -274,7 +277,7 @@ pub enum VaultError {
#[error("The given payment method is currently not supported in vault")]
PaymentMethodNotSupported,
#[error("Missing required field: {field_name}")]
MissingRequiredField { field_name: String },
MissingRequiredField { field_name: &'static str },
#[error("The card vault returned an unexpected response: {0:?}")]
UnexpectedResponseError(bytes::Bytes),
}
@ -306,9 +309,9 @@ pub enum ProcessTrackerError {
#[error("Failed to fetch processes from database")]
ProcessFetchingFailed,
#[error("Failed while fetching: {resource_name}")]
ResourceFetchingFailed { resource_name: String },
ResourceFetchingFailed { resource_name: &'static str },
#[error("Failed while executing: {flow}")]
FlowExecutionError { flow: String },
FlowExecutionError { flow: &'static str },
#[error("Not Implemented")]
NotImplemented,
#[error("Job not found")]

View File

@ -28,7 +28,7 @@ pub enum ApiErrorResponse {
#[error(error_type = ErrorType::InvalidRequestError, code = "IR_04", 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}.")]
MissingRequiredField { field_name: String },
MissingRequiredField { field_name: &'static str },
#[error(
error_type = ErrorType::InvalidRequestError, code = "IR_06",
message = "{field_name} contains invalid data. Expected format is {expected_format}."

View File

@ -86,9 +86,7 @@ impl ConnectorErrorExt for error_stack::Report<errors::ConnectorError> {
errors::ApiErrorResponse::PaymentAuthorizationFailed { data }
}
errors::ConnectorError::MissingRequiredField { field_name } => {
errors::ApiErrorResponse::MissingRequiredField {
field_name: field_name.clone(),
}
errors::ApiErrorResponse::MissingRequiredField { field_name }
}
errors::ConnectorError::NotImplemented(reason) => {
errors::ApiErrorResponse::NotImplemented {

View File

@ -257,7 +257,7 @@ where
let resource_id = api::PaymentIdTypeExt::get_payment_intent_id(&req.resource_id)
.change_context(errors::ApiErrorResponse::MissingRequiredField {
field_name: "payment_id".to_string(),
field_name: "payment_id",
})?;
let connector_data = api::ConnectorData::get_connector_by_name(

View File

@ -539,7 +539,7 @@ pub(crate) async fn call_payment_method(
}
}
None => Err(report!(errors::ApiErrorResponse::MissingRequiredField {
field_name: "customer".to_string()
field_name: "customer"
})
.attach_printable("Missing Customer Object")),
}
@ -568,12 +568,12 @@ pub(crate) async fn call_payment_method(
}
},
None => Err(report!(errors::ApiErrorResponse::MissingRequiredField {
field_name: "payment_method_type".to_string()
field_name: "payment_method_type"
})
.attach_printable("PaymentMethodType Required")),
},
None => Err(report!(errors::ApiErrorResponse::MissingRequiredField {
field_name: "payment_method_data".to_string()
field_name: "payment_method_data"
})
.attach_printable("PaymentMethodData required Or Card is already saved")),
}
@ -829,7 +829,7 @@ pub(crate) fn validate_payment_method_fields_present(
req.payment_method.is_none() && req.payment_method_data.is_some(),
|| {
Err(errors::ApiErrorResponse::MissingRequiredField {
field_name: "payent_method".to_string(),
field_name: "payent_method",
})
},
)?;
@ -840,7 +840,7 @@ pub(crate) fn validate_payment_method_fields_present(
&& req.payment_token.is_none(),
|| {
Err(errors::ApiErrorResponse::MissingRequiredField {
field_name: "payment_method_data".to_string(),
field_name: "payment_method_data",
})
},
)?;

View File

@ -477,7 +477,7 @@ impl<F: Clone> TryFrom<PaymentData<F>> for types::PaymentsCancelData {
.payment_attempt
.connector_transaction_id
.ok_or(errors::ApiErrorResponse::MissingRequiredField {
field_name: "connector_transaction_id".to_string(),
field_name: "connector_transaction_id",
})?,
cancellation_reason: payment_data.payment_attempt.cancellation_reason,
})

View File

@ -108,7 +108,7 @@ pub async fn trigger_refund_to_gateway(
let currency = payment_attempt.currency.ok_or_else(|| {
report!(errors::ApiErrorResponse::MissingRequiredField {
field_name: "currency".to_string()
field_name: "currency"
})
.attach_printable("Transaction in invalid")
})?;

View File

@ -64,9 +64,10 @@ mod storage {
.await
{
Ok(v) if v.contains(&HsetnxReply::KeyNotSet) => {
Err(errors::StorageError::DuplicateValue(
"Ephemeral key already exists".to_string(),
)
Err(errors::StorageError::DuplicateValue {
entity: "ephimeral key",
key: None,
}
.into())
}
Ok(_) => {

View File

@ -391,9 +391,10 @@ mod storage {
.serialize_and_set_hash_field_if_not_exist(&key, &field, &created_attempt)
.await
{
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
format!("Payment Attempt already exists for payment_id: {key}"),
))
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue {
entity: "payment attempt",
key: Some(key),
})
.into_report(),
Ok(HsetnxReply::KeySet) => {
let conn = pg_connection(&self.master_pool).await;

View File

@ -102,9 +102,10 @@ mod storage {
.serialize_and_set_hash_field_if_not_exist(&key, "pi", &created_intent)
.await
{
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue(
format!("Payment Intent already exists for payment_id: {key}"),
))
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue {
entity: "payment_intent",
key: Some(key),
})
.into_report(),
Ok(HsetnxReply::KeySet) => {
let redis_entry = kv::TypedSql {

View File

@ -128,7 +128,7 @@ impl QueueInterface for MockDb {
) -> CustomResult<Vec<storage::ProcessTracker>, ProcessTrackerError> {
// [#172]: Implement function for `MockDb`
Err(ProcessTrackerError::ResourceFetchingFailed {
resource_name: "consumer_tasks".to_string(),
resource_name: "consumer_tasks",
})?
}

View File

@ -305,13 +305,11 @@ mod storage {
.serialize_and_set_hash_field_if_not_exist(&key, &field, &created_refund)
.await
{
Ok(HsetnxReply::KeyNotSet) => {
Err(errors::StorageError::DuplicateValue(format!(
"Refund already exists refund_id: {}",
&created_refund.refund_id
)))
.into_report()
}
Ok(HsetnxReply::KeyNotSet) => Err(errors::StorageError::DuplicateValue {
entity: "refund",
key: Some(created_refund.refund_id),
})
.into_report(),
Ok(HsetnxReply::KeySet) => {
let conn = pg_connection(&self.master_pool).await;

View File

@ -204,7 +204,7 @@ pub fn check_client_secret_and_get_auth(
.get_client_secret()
.check_value_present("client_secret")
.map_err(|_| errors::ApiErrorResponse::MissingRequiredField {
field_name: "client_secret".to_owned(),
field_name: "client_secret",
})?;
return Ok((Box::new(PublishableKeyAuth), api::AuthFlow::Client));
}

View File

@ -7,18 +7,18 @@ use crate::{
};
pub trait OptionExt<T> {
fn check_value_present(&self, field_name: &str) -> RouterResult<()>;
fn check_value_present(&self, field_name: &'static str) -> RouterResult<()>;
fn get_required_value(self, field_name: &str) -> RouterResult<T>;
fn get_required_value(self, field_name: &'static str) -> RouterResult<T>;
fn parse_enum<E>(self, enum_name: &str) -> CustomResult<E, errors::ParsingError>
fn parse_enum<E>(self, enum_name: &'static str) -> CustomResult<E, errors::ParsingError>
where
T: AsRef<str>,
E: std::str::FromStr,
// Requirement for converting the `Err` variant of `FromStr` to `Report<Err>`
<E as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static;
fn parse_value<U>(self, type_name: &str) -> CustomResult<U, errors::ParsingError>
fn parse_value<U>(self, type_name: &'static str) -> CustomResult<U, errors::ParsingError>
where
T: ValueExt<U>,
U: serde::de::DeserializeOwned;
@ -30,26 +30,26 @@ impl<T> OptionExt<T> for Option<T>
where
T: std::fmt::Debug,
{
fn check_value_present(&self, field_name: &str) -> RouterResult<()> {
fn check_value_present(&self, field_name: &'static str) -> RouterResult<()> {
when(self.is_none(), || {
Err(Report::new(ApiErrorResponse::MissingRequiredField {
field_name: field_name.to_string(),
})
.attach_printable(format!("Missing required field {field_name} in {self:?}")))
Err(
Report::new(ApiErrorResponse::MissingRequiredField { field_name })
.attach_printable(format!("Missing required field {field_name} in {self:?}")),
)
})
}
fn get_required_value(self, field_name: &str) -> RouterResult<T> {
fn get_required_value(self, field_name: &'static str) -> RouterResult<T> {
match self {
Some(v) => Ok(v),
None => Err(Report::new(ApiErrorResponse::MissingRequiredField {
field_name: field_name.to_string(),
})
.attach_printable(format!("Missing required field {field_name} in {self:?}"))),
None => Err(
Report::new(ApiErrorResponse::MissingRequiredField { field_name })
.attach_printable(format!("Missing required field {field_name} in {self:?}")),
),
}
}
fn parse_enum<E>(self, enum_name: &str) -> CustomResult<E, errors::ParsingError>
fn parse_enum<E>(self, enum_name: &'static str) -> CustomResult<E, errors::ParsingError>
where
T: AsRef<str>,
E: std::str::FromStr,
@ -65,7 +65,7 @@ where
.attach_printable_lazy(|| format!("Invalid {{ {enum_name}: {value:?} }} "))
}
fn parse_value<U>(self, type_name: &str) -> CustomResult<U, errors::ParsingError>
fn parse_value<U>(self, type_name: &'static str) -> CustomResult<U, errors::ParsingError>
where
T: ValueExt<U>,
U: serde::de::DeserializeOwned,