diff --git a/crates/router/src/compatibility/stripe/errors.rs b/crates/router/src/compatibility/stripe/errors.rs index f9488e90c0..782cdf7c90 100644 --- a/crates/router/src/compatibility/stripe/errors.rs +++ b/crates/router/src/compatibility/stripe/errors.rs @@ -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 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 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, diff --git a/crates/router/src/connector/adyen/transformers.rs b/crates/router/src/connector/adyen/transformers.rs index eb886514e1..245e1c3549 100644 --- a/crates/router/src/connector/adyen/transformers.rs +++ b/crates/router/src/connector/adyen/transformers.rs @@ -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, diff --git a/crates/router/src/connector/authorizedotnet/transformers.rs b/crates/router/src/connector/authorizedotnet/transformers.rs index c9f339fce2..05630a7005 100644 --- a/crates/router/src/connector/authorizedotnet/transformers.rs +++ b/crates/router/src/connector/authorizedotnet/transformers.rs @@ -316,7 +316,7 @@ impl }) .transpose() .change_context(errors::ConnectorError::MissingRequiredField { - field_name: "connector_metadata".to_string(), + field_name: "connector_metadata", })?; Ok(Self { @@ -372,7 +372,7 @@ impl TryFrom<&types::RefundsRouterData> 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 TryFrom<&types::RefundsRouterData> 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(), diff --git a/crates/router/src/connector/klarna/transformers.rs b/crates/router/src/connector/klarna/transformers.rs index 7e2dbd8e9b..14810ba672 100644 --- a/crates/router/src/connector/klarna/transformers.rs +++ b/crates/router/src/connector/klarna/transformers.rs @@ -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" })), } } diff --git a/crates/router/src/connector/payu/transformers.rs b/crates/router/src/connector/payu/transformers.rs index c62164af9e..20a2c6f4bb 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/router/src/connector/payu/transformers.rs @@ -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 TryFrom<&types::RefundsRouterData> 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, diff --git a/crates/router/src/connector/stripe/transformers.rs b/crates/router/src/connector/stripe/transformers.rs index 2f18b3fd29..865d7a243a 100644 --- a/crates/router/src/connector/stripe/transformers.rs +++ b/crates/router/src/connector/stripe/transformers.rs @@ -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", }) })?; } diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index a8ea25e785..cd2d9db446 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -7,11 +7,11 @@ use crate::{ }; pub fn missing_field_err( - message: &str, + message: &'static str, ) -> Box error_stack::Report + '_> { - Box::new(|| { + Box::new(move || { errors::ConnectorError::MissingRequiredField { - field_name: message.to_string(), + field_name: message, } .into() }) diff --git a/crates/router/src/connector/worldline/transformers.rs b/crates/router/src/connector/worldline/transformers.rs index 7c363f4a90..f2eefdf8ba 100644 --- a/crates/router/src/connector/worldline/transformers.rs +++ b/crates/router/src/connector/worldline/transformers.rs @@ -211,7 +211,7 @@ fn build_customer_info( ) -> Result> { 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| { diff --git a/crates/router/src/connector/worldpay/response.rs b/crates/router/src/connector/worldpay/response.rs index 5102ac9528..e25365d0e4 100644 --- a/crates/router/src/connector/worldpay/response.rs +++ b/crates/router/src/connector/worldpay/response.rs @@ -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() }) diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index 70018ff8b7..88427b3ee9 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -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> 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, diff --git a/crates/router/src/core/errors.rs b/crates/router/src/core/errors.rs index 7f3301ee1a..d7532c1152 100644 --- a/crates/router/src/core/errors.rs +++ b/crates/router/src/core/errors.rs @@ -54,8 +54,11 @@ pub enum StorageError { DatabaseError(error_stack::Report), #[error("ValueNotFound: {0}")] ValueNotFound(String), - #[error("DuplicateValue: {0}")] - DuplicateValue(String), + #[error("DuplicateValue: {entity} already exists {key:?}")] + DuplicateValue { + entity: &'static str, + key: Option, + }, #[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")] diff --git a/crates/router/src/core/errors/api_error_response.rs b/crates/router/src/core/errors/api_error_response.rs index 1b01a64e85..16318e737c 100644 --- a/crates/router/src/core/errors/api_error_response.rs +++ b/crates/router/src/core/errors/api_error_response.rs @@ -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}." diff --git a/crates/router/src/core/errors/utils.rs b/crates/router/src/core/errors/utils.rs index bc6659be3d..8389beeeeb 100644 --- a/crates/router/src/core/errors/utils.rs +++ b/crates/router/src/core/errors/utils.rs @@ -86,9 +86,7 @@ impl ConnectorErrorExt for error_stack::Report { 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 { diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index afb431fe6c..9cfbabb1ce 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -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( diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index f8afbd3ae2..ed76aba56b 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -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", }) }, )?; diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 0471f337c9..51c4d35ce1 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -477,7 +477,7 @@ impl TryFrom> 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, }) diff --git a/crates/router/src/core/refunds.rs b/crates/router/src/core/refunds.rs index c10d08597e..6e8be43e25 100644 --- a/crates/router/src/core/refunds.rs +++ b/crates/router/src/core/refunds.rs @@ -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") })?; diff --git a/crates/router/src/db/ephemeral_key.rs b/crates/router/src/db/ephemeral_key.rs index 15c9a6f673..1969cbbc83 100644 --- a/crates/router/src/db/ephemeral_key.rs +++ b/crates/router/src/db/ephemeral_key.rs @@ -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(_) => { diff --git a/crates/router/src/db/payment_attempt.rs b/crates/router/src/db/payment_attempt.rs index 28e89f8c48..45d8877cd1 100644 --- a/crates/router/src/db/payment_attempt.rs +++ b/crates/router/src/db/payment_attempt.rs @@ -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; diff --git a/crates/router/src/db/payment_intent.rs b/crates/router/src/db/payment_intent.rs index bb4cc946e0..e3cc2b1c23 100644 --- a/crates/router/src/db/payment_intent.rs +++ b/crates/router/src/db/payment_intent.rs @@ -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 { diff --git a/crates/router/src/db/queue.rs b/crates/router/src/db/queue.rs index 4396c31b72..ce0401886a 100644 --- a/crates/router/src/db/queue.rs +++ b/crates/router/src/db/queue.rs @@ -128,7 +128,7 @@ impl QueueInterface for MockDb { ) -> CustomResult, ProcessTrackerError> { // [#172]: Implement function for `MockDb` Err(ProcessTrackerError::ResourceFetchingFailed { - resource_name: "consumer_tasks".to_string(), + resource_name: "consumer_tasks", })? } diff --git a/crates/router/src/db/refund.rs b/crates/router/src/db/refund.rs index 821138431a..3b5fefedad 100644 --- a/crates/router/src/db/refund.rs +++ b/crates/router/src/db/refund.rs @@ -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; diff --git a/crates/router/src/services/authentication.rs b/crates/router/src/services/authentication.rs index 583eb07f8a..7eb0e9242a 100644 --- a/crates/router/src/services/authentication.rs +++ b/crates/router/src/services/authentication.rs @@ -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)); } diff --git a/crates/router/src/utils/ext_traits.rs b/crates/router/src/utils/ext_traits.rs index b087882524..a27da6d49e 100644 --- a/crates/router/src/utils/ext_traits.rs +++ b/crates/router/src/utils/ext_traits.rs @@ -7,18 +7,18 @@ use crate::{ }; pub trait OptionExt { - 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; + fn get_required_value(self, field_name: &'static str) -> RouterResult; - fn parse_enum(self, enum_name: &str) -> CustomResult + fn parse_enum(self, enum_name: &'static str) -> CustomResult where T: AsRef, E: std::str::FromStr, // Requirement for converting the `Err` variant of `FromStr` to `Report` ::Err: std::error::Error + Send + Sync + 'static; - fn parse_value(self, type_name: &str) -> CustomResult + fn parse_value(self, type_name: &'static str) -> CustomResult where T: ValueExt, U: serde::de::DeserializeOwned; @@ -30,26 +30,26 @@ impl OptionExt for Option 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 { + fn get_required_value(self, field_name: &'static str) -> RouterResult { 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(self, enum_name: &str) -> CustomResult + fn parse_enum(self, enum_name: &'static str) -> CustomResult where T: AsRef, E: std::str::FromStr, @@ -65,7 +65,7 @@ where .attach_printable_lazy(|| format!("Invalid {{ {enum_name}: {value:?} }} ")) } - fn parse_value(self, type_name: &str) -> CustomResult + fn parse_value(self, type_name: &'static str) -> CustomResult where T: ValueExt, U: serde::de::DeserializeOwned, diff --git a/crates/router/tests/connectors/worldline.rs b/crates/router/tests/connectors/worldline.rs index 05a7294f37..8ae7ded8de 100644 --- a/crates/router/tests/connectors/worldline.rs +++ b/crates/router/tests/connectors/worldline.rs @@ -157,7 +157,7 @@ async fn should_throw_missing_required_field_for_country() { assert_eq!( *response.unwrap_err().current_context(), errors::ConnectorError::MissingRequiredField { - field_name: String::from("billing.address.country") + field_name: "billing.address.country" } ) }