Repository: juspay/hyperswitch
File: crates/api_models/src/routing.rs (Rust)

Code before:
    #[schema(value_type = String)]
    pub profile_id: common_utils::id_type::ProfileId,
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct RoutingConfigRequest {
    pub name: Option<String>,
    pub description: Option<String>,
    pub algorithm: Option<StaticRoutingAlgorithm>,
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<common_utils::id_type::ProfileId>,
    pub transaction_type: Option<TransactionType>,
}

#[cfg(feature = "v1")]
impl RoutingConfigRequest {
    pub fn validate_name_length(&self) -> Result<(), ValidationError> {
        if let Some(name) = &self.name {
            if name.len() > MAX_NAME_LENGTH {
                return Err(ValidationError::InvalidValue {
                    message: format!(
                        "Length of name field must not exceed {} characters",
                        MAX_NAME_LENGTH
                    ),
                });
            }
        }
        Ok(())
    }
}

#[derive(Debug, serde::Serialize, ToSchema)]
pub struct ProfileDefaultRoutingConfig {
    #[schema(value_type = String)]
    pub profile_id: common_utils::id_type::ProfileId,
    pub connectors: Vec<RoutableConnectorChoice>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct RoutingRetrieveQuery {
    pub limit: Option<u16>,
    pub offset: Option<u8>,
    pub transaction_type: Option<TransactionType>,
}

#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)]
pub struct RoutingActivatePayload {
    pub transaction_type: Option<TransactionType>,
}


Review comment (suggestion):
Also this is just a api level handling, returning this error message won't be enough from the merchant's view point.
But we need to also handle it in the fronted for the better experience. 

For example we can have a validation in the fronted where is the name is greater than 64 character the create run button will be displayed.

Code after:
    #[schema(value_type = String)]
    pub profile_id: common_utils::id_type::ProfileId,
}

#[cfg(feature = "v1")]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct RoutingConfigRequest {
    #[schema(value_type = Option<String>)]
    pub name: Option<RoutingConfigName>,
    pub description: Option<String>,
    pub algorithm: Option<StaticRoutingAlgorithm>,
    #[schema(value_type = Option<String>)]
    pub profile_id: Option<common_utils::id_type::ProfileId>,
    pub transaction_type: Option<TransactionType>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(try_from = "String")]
#[schema(value_type = String)]
pub struct RoutingConfigName(String);

impl RoutingConfigName {
    pub fn new(name: impl Into<String>) -> Result<Self, ValidationError> {
        let name = name.into();
        if name.len() > MAX_NAME_LENGTH {
            return Err(ValidationError::InvalidValue {
                message: format!(
                    "Length of name field must not exceed {} characters",
                    MAX_NAME_LENGTH
                ),
            });
        }

        Ok(Self(name))
    }
}

impl TryFrom<String> for RoutingConfigName {
    type Error = ValidationError;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        Self::new(value)
    }
}

impl Deref for RoutingConfigName {
    type Target = String;

    fn deref(&self) -> &Self::Target {
        &self.0
    }