Skip to content

Commit

Permalink
feat(routing): Updated openapi spec to include routing APIs (#3012)
Browse files Browse the repository at this point in the history
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
Co-authored-by: shashank_attarde <[email protected]>
Co-authored-by: Narayan Bhat <[email protected]>
Co-authored-by: Aprabhat19 <[email protected]>
  • Loading branch information
5 people authored Dec 19, 2023
1 parent 3cffc89 commit 3ce53c7
Show file tree
Hide file tree
Showing 14 changed files with 1,768 additions and 213 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions crates/api_models/src/admin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ pub struct MerchantAccountCreate {
pub webhook_details: Option<WebhookDetails>,

/// The routing algorithm to be used for routing payments to desired connectors
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "stripe"}))]
#[serde(skip)]
#[schema(deprecated)]
pub routing_algorithm: Option<serde_json::Value>,

/// The routing algorithm to be used for routing payouts to desired connectors
Expand Down Expand Up @@ -135,7 +136,8 @@ pub struct MerchantAccountUpdate {
pub webhook_details: Option<WebhookDetails>,

/// The routing algorithm to be used for routing payments to desired connectors
#[schema(value_type = Option<Object>,example = json!({"type": "single", "data": "stripe"}))]
#[serde(skip)]
#[schema(deprecated)]
pub routing_algorithm: Option<serde_json::Value>,

/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
Expand Down Expand Up @@ -233,7 +235,8 @@ pub struct MerchantAccountResponse {
pub webhook_details: Option<serde_json::Value>,

/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
#[schema(value_type = Option<RoutingAlgorithm>, max_length = 255, example = "custom")]
#[serde(skip)]
#[schema(deprecated)]
pub routing_algorithm: Option<serde_json::Value>,

/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
Expand Down
2 changes: 0 additions & 2 deletions crates/api_models/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@ use utoipa::ToSchema;
serde::Serialize,
strum::Display,
strum::EnumString,
ToSchema,
)]

/// The routing algorithm to be used to process the incoming request from merchant to outgoing payment processor or payment method. The default is 'Custom'
#[schema(example = "custom")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RoutingAlgorithm {
Expand Down
4 changes: 2 additions & 2 deletions crates/api_models/src/payments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ pub struct PaymentsRequest {
#[schema(max_length = 255, example = "merchant_1668273825")]
pub merchant_id: Option<String>,

#[schema(value_type = Option<RoutingAlgorithm>, example = json!({
#[schema(value_type = Option<StraightThroughAlgorithm>, example = json!({
"type": "single",
"data": "stripe"
"data": {"connector": "stripe", "merchant_connector_id": "mca_123"}
}))]
pub routing: Option<serde_json::Value>,

Expand Down
40 changes: 24 additions & 16 deletions crates/api_models/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ use std::fmt::Debug;

use common_utils::errors::ParsingError;
use error_stack::IntoReport;
use euclid::{
pub use euclid::{
dssa::types::EuclidAnalysable,
frontend::{
ast,
dir::{DirKeyKind, EuclidDirFilter},
},
};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

use crate::enums::{self, RoutableConnectors};

#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", content = "data", rename_all = "snake_case")]
pub enum ConnectorSelection {
Priority(Vec<RoutableConnectorChoice>),
Expand All @@ -31,15 +32,15 @@ impl ConnectorSelection {
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct RoutingConfigRequest {
pub name: Option<String>,
pub description: Option<String>,
pub algorithm: Option<RoutingAlgorithm>,
pub profile_id: Option<String>,
}

#[derive(Debug, serde::Serialize)]
#[derive(Debug, serde::Serialize, ToSchema)]
pub struct ProfileDefaultRoutingConfig {
pub profile_id: String,
pub connectors: Vec<RoutableConnectorChoice>,
Expand All @@ -60,19 +61,21 @@ pub struct RoutingRetrieveLinkQuery {
pub profile_id: Option<String>,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
/// Response of the retrieved routing configs for a merchant account
pub struct RoutingRetrieveResponse {
pub algorithm: Option<MerchantRoutingAlgorithm>,
}

#[derive(Debug, serde::Serialize)]
#[derive(Debug, serde::Serialize, ToSchema)]
#[serde(untagged)]
pub enum LinkedRoutingConfigRetrieveResponse {
MerchantAccountBased(RoutingRetrieveResponse),
ProfileBased(Vec<RoutingDictionaryRecord>),
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
/// Routing Algorithm specific to merchants
pub struct MerchantRoutingAlgorithm {
pub id: String,
#[cfg(feature = "business_profile_routing")]
Expand Down Expand Up @@ -153,14 +156,14 @@ impl EuclidAnalysable for ConnectorSelection {
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct ConnectorVolumeSplit {
pub connector: RoutableConnectorChoice,
pub split: u8,
}

#[cfg(feature = "connector_choice_bcompat")]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema)]
pub enum RoutableChoiceKind {
OnlyConnector,
FullStruct,
Expand All @@ -180,15 +183,18 @@ pub enum RoutableChoiceSerde {
},
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
#[cfg_attr(
feature = "connector_choice_bcompat",
serde(from = "RoutableChoiceSerde"),
serde(into = "RoutableChoiceSerde")
)]
#[cfg_attr(not(feature = "connector_choice_bcompat"), derive(PartialEq, Eq))]

/// Routable Connector chosen for a payment
pub struct RoutableConnectorChoice {
#[cfg(feature = "connector_choice_bcompat")]
#[serde(skip)]
pub choice_kind: RoutableChoiceKind,
pub connector: RoutableConnectors,
#[cfg(feature = "connector_choice_mca_id")]
Expand Down Expand Up @@ -322,7 +328,7 @@ impl DetailedConnectorChoice {
}
}

#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, strum::Display)]
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize, strum::Display, ToSchema)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RoutingAlgorithmKind {
Expand All @@ -339,17 +345,19 @@ pub struct RoutingPayloadWrapper {
pub profile_id: String,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(
tag = "type",
content = "data",
rename_all = "snake_case",
try_from = "RoutingAlgorithmSerde"
)]
/// Routing Algorithm kind
pub enum RoutingAlgorithm {
Single(Box<RoutableConnectorChoice>),
Priority(Vec<RoutableConnectorChoice>),
VolumeSplit(Vec<ConnectorVolumeSplit>),
#[schema(value_type=ProgramConnectorSelection)]
Advanced(euclid::frontend::ast::Program<ConnectorSelection>),
}

Expand Down Expand Up @@ -390,7 +398,7 @@ impl TryFrom<RoutingAlgorithmSerde> for RoutingAlgorithm {
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(
tag = "type",
content = "data",
Expand Down Expand Up @@ -516,7 +524,7 @@ impl RoutingAlgorithmRef {
}
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]

pub struct RoutingDictionaryRecord {
pub id: String,
Expand All @@ -529,14 +537,14 @@ pub struct RoutingDictionaryRecord {
pub modified_at: i64,
}

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct RoutingDictionary {
pub merchant_id: String,
pub active_id: Option<String>,
pub records: Vec<RoutingDictionaryRecord>,
}

#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[derive(serde::Serialize, serde::Deserialize, Debug, ToSchema)]
#[serde(untagged)]
pub enum RoutingKind {
Config(RoutingDictionary),
Expand Down
2 changes: 2 additions & 0 deletions crates/common_enums/src/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ pub enum AttemptStatus {
strum::EnumString,
strum::EnumIter,
strum::EnumVariantNames,
ToSchema,
)]
#[router_derive::diesel_enum(storage_type = "db_enum")]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
/// Connectors eligible for payments routing
pub enum RoutableConnectors {
#[cfg(feature = "dummy_connector")]
#[serde(rename = "phonypay")]
Expand Down
1 change: 1 addition & 0 deletions crates/euclid/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ serde = { version = "1.0.193", features = ["derive", "rc"] }
serde_json = "1.0.108"
strum = { version = "0.25", features = ["derive"] }
thiserror = "1.0.43"
utoipa = { version = "3.3.0", features = ["preserve_order"] }

# First party dependencies
common_enums = { version = "0.1.0", path = "../common_enums" }
Expand Down
54 changes: 46 additions & 8 deletions crates/euclid/src/frontend/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod parser;

use common_enums::RoutableConnectors;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

use crate::types::{DataType, Metadata};

Expand All @@ -14,14 +15,14 @@ pub struct ConnectorChoice {
pub sub_label: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)]
pub struct MetadataValue {
pub key: String,
pub value: String,
}

/// Represents a value in the DSL
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", content = "value", rename_all = "snake_case")]
pub enum ValueType {
/// Represents a number literal
Expand Down Expand Up @@ -60,15 +61,15 @@ impl ValueType {
}

/// Represents a number comparison for "NumberComparisonArrayValue"
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct NumberComparison {
pub comparison_type: ComparisonType,
pub number: i64,
}

/// Conditional comparison type
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum ComparisonType {
Equal,
Expand All @@ -80,7 +81,7 @@ pub enum ComparisonType {
}

/// Represents a single comparison condition.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct Comparison {
/// The left hand side which will always be a domain input identifier like "payment.method.cardtype"
Expand All @@ -92,6 +93,7 @@ pub struct Comparison {
/// Additional metadata that the Static Analyzer and Backend does not touch.
/// This can be used to store useful information for the frontend and is required for communication
/// between the static analyzer and the frontend.
#[schema(value_type=HashMap<String, serde_json::Value>)]
pub metadata: Metadata,
}

Expand All @@ -112,9 +114,10 @@ pub type IfCondition = Vec<Comparison>;
/// }
/// }
/// ```
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct IfStatement {
#[schema(value_type=Vec<Comparison>)]
pub condition: IfCondition,
pub nested: Option<Vec<IfStatement>>,
}
Expand All @@ -134,8 +137,9 @@ pub struct IfStatement {
/// }
/// ```
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
#[aliases(RuleConnectorSelection = Rule<ConnectorSelection>)]
pub struct Rule<O> {
pub name: String,
#[serde(alias = "routingOutput")]
Expand All @@ -145,10 +149,44 @@ pub struct Rule<O> {

/// The program, having a default connector selection and
/// a bunch of rules. Also can hold arbitrary metadata.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
#[aliases(ProgramConnectorSelection = Program<ConnectorSelection>)]
pub struct Program<O> {
pub default_selection: O,
#[schema(value_type=RuleConnectorSelection)]
pub rules: Vec<Rule<O>>,
#[schema(value_type=HashMap<String, serde_json::Value>)]
pub metadata: Metadata,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct RoutableConnectorChoice {
#[cfg(feature = "connector_choice_bcompat")]
#[serde(skip)]
pub choice_kind: RoutableChoiceKind,
// pub connector: RoutableConnectors,
#[cfg(feature = "connector_choice_mca_id")]
pub merchant_connector_id: Option<String>,
#[cfg(not(feature = "connector_choice_mca_id"))]
pub sub_label: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize, ToSchema)]
pub enum RoutableChoiceKind {
OnlyConnector,
FullStruct,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct ConnectorVolumeSplit {
pub connector: RoutableConnectorChoice,
pub split: u8,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(tag = "type", content = "data", rename_all = "snake_case")]
pub enum ConnectorSelection {
Priority(Vec<RoutableConnectorChoice>),
VolumeSplit(Vec<ConnectorVolumeSplit>),
}
Loading

0 comments on commit 3ce53c7

Please sign in to comment.