integrationos_domain/domain/connection/
api_model_config.rs

1use http::HeaderMap;
2use js_sandbox_ios::Script;
3use serde::{de::DeserializeOwned, Deserialize, Serialize};
4use serde_json::Value;
5use std::collections::BTreeMap;
6
7use crate::{prelude::schema::json_schema::JsonSchema, IntegrationOSError, InternalError};
8
9#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
10#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
11#[serde(rename_all = "camelCase")]
12pub struct ApiModelConfig {
13    pub base_url: String,
14    pub path: String,
15    pub auth_method: AuthMethod,
16    #[serde(
17        with = "http_serde_ext::header_map::option",
18        skip_serializing_if = "Option::is_none",
19        default
20    )]
21    pub headers: Option<HeaderMap>,
22    #[serde(skip_serializing_if = "Option::is_none")]
23    pub query_params: Option<BTreeMap<String, String>>,
24    #[serde(default, skip_serializing_if = "Option::is_none")]
25    pub content: Option<ContentType>,
26    pub schemas: SchemasInput,
27    pub samples: SamplesInput,
28    pub responses: Vec<ResponseBody>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub paths: Option<ModelPaths>,
31}
32
33#[derive(Debug, Clone, PartialEq, Deserialize, Serialize, Default)]
34#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
35#[serde(rename_all = "camelCase")]
36/// This type is a combination of the `Method` and the `ContentType` of the request
37pub enum ContentType {
38    Json,
39    Form,
40    #[default]
41    Other,
42}
43
44impl ApiModelConfig {
45    /// Returns the full path of the API endpoint
46    /// e.g. https://api.example.com/v1/users
47    pub fn uri(&self) -> String {
48        let mut base_url = self.base_url.to_owned();
49        let path = self.path.to_owned();
50        if base_url.ends_with('/') && path.starts_with('/') {
51            base_url.pop();
52        }
53        base_url + &path
54    }
55}
56
57#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
58#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
59pub struct ModelPaths {
60    pub request: Option<RequestModelPaths>,
61    pub response: Option<ResponseModelPaths>,
62}
63
64#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
65#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
66#[serde(rename_all = "camelCase")]
67pub struct RequestModelPaths {
68    pub object: Option<String>,
69}
70
71#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
72#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
73#[serde(rename_all = "camelCase")]
74pub struct ResponseModelPaths {
75    pub object: Option<String>,
76    pub id: Option<String>,
77    pub cursor: Option<String>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
81#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
82#[serde(rename_all = "camelCase")]
83pub struct SamplesInput {
84    #[serde(
85        with = "http_serde_ext::header_map::option",
86        skip_serializing_if = "Option::is_none",
87        default
88    )]
89    pub headers: Option<http::HeaderMap>,
90    pub query_params: Option<Value>,
91    pub path_params: Option<Value>,
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub body: Option<Value>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
97#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
98#[serde(rename_all = "camelCase")]
99pub struct SchemasInput {
100    pub headers: Option<JsonSchema>,
101    pub query_params: Option<JsonSchema>,
102    pub path_params: Option<JsonSchema>,
103    pub body: Option<JsonSchema>,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
107#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
108#[serde(rename_all = "camelCase")]
109pub struct ResponseBody {
110    pub status_code: u16,
111    #[serde(
112        with = "http_serde_ext::header_map::option",
113        skip_serializing_if = "Option::is_none",
114        default
115    )]
116    pub headers: Option<http::HeaderMap>,
117    pub body: Option<Value>,
118}
119
120#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
121#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
122#[serde(tag = "type")]
123pub enum AuthMethod {
124    BearerToken {
125        value: String,
126    },
127    ApiKey {
128        key: String,
129        value: String,
130    },
131    BasicAuth {
132        username: String,
133        password: String,
134    },
135    OAuthLegacy {
136        #[serde(rename = "hashAlgorithm")]
137        hash_algorithm: OAuthLegacyHashAlgorithm,
138        #[serde(skip_serializing_if = "Option::is_none")]
139        realm: Option<String>,
140    },
141    OAuth,
142    None,
143}
144
145#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
146#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
147pub enum OAuthLegacyHashAlgorithm {
148    #[serde(rename = "HMAC-SHA1")]
149    HmacSha1,
150    #[serde(rename = "HMAC-SHA256")]
151    HmacSha256,
152    #[serde(rename = "HMAC-SHA512")]
153    HmacSha512,
154    #[serde(rename = "PLAINTEXT")]
155    PlainText,
156}
157
158#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct Function(pub Compute);
161
162#[cfg(feature = "dummy")]
163impl<T> fake::Dummy<T> for Function {
164    fn dummy_with_rng<R: rand::prelude::Rng + ?Sized>(_: &T, _: &mut R) -> Self {
165        use fake::{Fake, Faker};
166        Function(Compute {
167            entry: Faker.fake(),
168            function: Faker.fake(),
169            language: Lang::JavaScript,
170        })
171    }
172}
173
174impl Function {
175    pub fn compute<T: DeserializeOwned>(&self, payload: &Value) -> Result<T, IntegrationOSError> {
176        let mut js_code = Script::from_string(&self.0.function).map_err(|e| {
177            InternalError::script_error(
178                &e.to_string(),
179                Some("Failed to create script from function"),
180            )
181        })?;
182        let response: T = js_code.call(&self.0.entry, (payload,)).map_err(|e| {
183            InternalError::script_error(&e.to_string(), Some("Failed to call function"))
184        })?;
185
186        Ok(response)
187    }
188}
189
190#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize)]
191#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
192#[serde(rename_all = "camelCase")]
193pub struct Compute {
194    pub entry: String,
195    pub function: String,
196    pub language: Lang,
197}
198
199#[derive(Debug, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, Default)]
200#[cfg_attr(feature = "dummy", derive(fake::Dummy))]
201#[serde(rename_all = "lowercase")]
202pub enum Lang {
203    #[default]
204    JavaScript,
205    TypeScript,
206    Rust,
207}