Skip to content

Commit e750344

Browse files
feat(nango): add integration.rs with list/get/create/update/delete endpoints (#3712)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: yujonglee <yujonglee.dev@gmail.com>
1 parent cad0c83 commit e750344

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

crates/nango/src/integration.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
use crate::client::{NangoClient, append_query, check_response, parse_response};
2+
use crate::common_derives;
3+
use crate::connect_session::DataWrapper;
4+
5+
common_derives! {
6+
pub struct Integration {
7+
pub unique_key: String,
8+
pub display_name: String,
9+
pub provider: String,
10+
#[serde(skip_serializing_if = "Option::is_none")]
11+
pub logo: Option<String>,
12+
pub created_at: String,
13+
pub updated_at: String,
14+
}
15+
}
16+
17+
common_derives! {
18+
pub struct IntegrationFull {
19+
pub unique_key: String,
20+
pub display_name: String,
21+
pub provider: String,
22+
#[serde(skip_serializing_if = "Option::is_none")]
23+
pub logo: Option<String>,
24+
pub created_at: String,
25+
pub updated_at: String,
26+
#[serde(skip_serializing_if = "Option::is_none")]
27+
pub webhook_url: Option<String>,
28+
#[serde(skip_serializing_if = "Option::is_none")]
29+
pub credentials: Option<IntegrationCredentials>,
30+
}
31+
}
32+
33+
common_derives! {
34+
#[serde(tag = "type")]
35+
pub enum IntegrationCredentials {
36+
#[serde(rename = "OAUTH1")]
37+
OAuth1 {
38+
client_id: String,
39+
client_secret: String,
40+
#[serde(skip_serializing_if = "Option::is_none")]
41+
scopes: Option<String>,
42+
#[serde(skip_serializing_if = "Option::is_none")]
43+
webhook_secret: Option<String>,
44+
},
45+
#[serde(rename = "OAUTH2")]
46+
OAuth2 {
47+
client_id: String,
48+
client_secret: String,
49+
#[serde(skip_serializing_if = "Option::is_none")]
50+
scopes: Option<String>,
51+
#[serde(skip_serializing_if = "Option::is_none")]
52+
webhook_secret: Option<String>,
53+
},
54+
#[serde(rename = "TBA")]
55+
Tba {
56+
client_id: String,
57+
client_secret: String,
58+
#[serde(skip_serializing_if = "Option::is_none")]
59+
scopes: Option<String>,
60+
#[serde(skip_serializing_if = "Option::is_none")]
61+
webhook_secret: Option<String>,
62+
},
63+
#[serde(rename = "APP")]
64+
App {
65+
app_id: String,
66+
app_link: String,
67+
private_key: String,
68+
},
69+
#[serde(rename = "CUSTOM")]
70+
Custom {
71+
client_id: String,
72+
client_secret: String,
73+
app_id: String,
74+
app_link: String,
75+
private_key: String,
76+
},
77+
}
78+
}
79+
80+
common_derives! {
81+
pub struct CreateIntegrationRequest {
82+
pub unique_key: String,
83+
pub provider: String,
84+
#[serde(skip_serializing_if = "Option::is_none")]
85+
pub display_name: Option<String>,
86+
#[serde(skip_serializing_if = "Option::is_none")]
87+
pub credentials: Option<IntegrationCredentials>,
88+
}
89+
}
90+
91+
common_derives! {
92+
#[derive(Default)]
93+
pub struct UpdateIntegrationRequest {
94+
#[serde(skip_serializing_if = "Option::is_none")]
95+
pub unique_key: Option<String>,
96+
#[serde(skip_serializing_if = "Option::is_none")]
97+
pub display_name: Option<String>,
98+
#[serde(skip_serializing_if = "Option::is_none")]
99+
pub credentials: Option<IntegrationCredentials>,
100+
}
101+
}
102+
103+
impl NangoClient {
104+
pub async fn list_integrations(&self) -> Result<Vec<Integration>, crate::Error> {
105+
let mut url = self.api_base.clone();
106+
url.set_path("/integrations");
107+
108+
let response = self.client.get(url).send().await?;
109+
let wrapper: DataWrapper<Vec<Integration>> = parse_response(response).await?;
110+
Ok(wrapper.data)
111+
}
112+
113+
pub async fn get_integration(
114+
&self,
115+
unique_key: impl std::fmt::Display,
116+
include: &[&str],
117+
) -> Result<IntegrationFull, crate::Error> {
118+
let mut url = self.api_base.clone();
119+
url.set_path(&format!("/integrations/{}", unique_key));
120+
121+
for item in include {
122+
append_query(&mut url, "include", item);
123+
}
124+
125+
let response = self.client.get(url).send().await?;
126+
let wrapper: DataWrapper<IntegrationFull> = parse_response(response).await?;
127+
Ok(wrapper.data)
128+
}
129+
130+
pub async fn create_integration(
131+
&self,
132+
req: CreateIntegrationRequest,
133+
) -> Result<Vec<Integration>, crate::Error> {
134+
let mut url = self.api_base.clone();
135+
url.set_path("/integrations");
136+
137+
let response = self.client.post(url).json(&req).send().await?;
138+
let wrapper: DataWrapper<Vec<Integration>> = parse_response(response).await?;
139+
Ok(wrapper.data)
140+
}
141+
142+
pub async fn update_integration(
143+
&self,
144+
unique_key: impl std::fmt::Display,
145+
req: UpdateIntegrationRequest,
146+
) -> Result<Integration, crate::Error> {
147+
let mut url = self.api_base.clone();
148+
url.set_path(&format!("/integrations/{}", unique_key));
149+
150+
let response = self.client.patch(url).json(&req).send().await?;
151+
let wrapper: DataWrapper<Integration> = parse_response(response).await?;
152+
Ok(wrapper.data)
153+
}
154+
155+
pub async fn delete_integration(
156+
&self,
157+
unique_key: impl std::fmt::Display,
158+
) -> Result<(), crate::Error> {
159+
let mut url = self.api_base.clone();
160+
url.set_path(&format!("/integrations/{}", unique_key));
161+
162+
let response = self.client.delete(url).send().await?;
163+
check_response(response).await?;
164+
Ok(())
165+
}
166+
}

crates/nango/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@ mod client;
22
mod connect_session;
33
mod connection;
44
mod error;
5+
mod integration;
56
pub mod proxy;
67
mod types;
78

89
pub use client::*;
910
pub use connect_session::*;
1011
pub use connection::*;
1112
pub use error::*;
13+
pub use integration::*;
1214
pub use proxy::NangoProxyBuilder;
1315
pub use types::*;
1416

0 commit comments

Comments
 (0)