hubspot_contacts/
lib.rs

1//! A fully generated & opinionated API client for the Hubspot Contacts API.
2//!
3//! [![docs.rs](https://docs.rs/hubspot-contacts/badge.svg)](https://docs.rs/hubspot-contacts)
4//!
5//! ## API Details
6//!
7//!
8//!
9//!
10//!
11//!
12//!
13//!
14//! ## Client Details
15//!
16//!
17//!
18//! The documentation for the crate is generated
19//! along with the code to make this library easy to use.
20//!
21//!
22//! To install the library, add the following to your `Cargo.toml` file.
23//!
24//! ```toml
25//! [dependencies]
26//! hubspot-contacts = "0.1.2"
27//! ```
28//!
29//! ## Basic example
30//!
31//! Typical use will require intializing a `Client`. This requires
32//! a user agent string and set of credentials.
33//!
34//! ```rust,no_run
35//! use hubspot_contacts::Client;
36//!
37//! let client = Client::new(String::from("api-key"));
38//! ```
39//!
40//! Alternatively, the library can search for most of the variables required for
41//! the client in the environment:
42//!
43//! - `HUBSPOT_CONTACTS_API_TOKEN`
44//!
45//!
46//! And then you can create a client from the environment.
47//!
48//! ```rust,no_run
49//! use hubspot_contacts::Client;
50//!
51//! let client = Client::new_from_env();
52//! ```
53#![allow(elided_named_lifetimes)]
54#![allow(missing_docs)]
55#![allow(unused_imports)]
56#![allow(clippy::needless_lifetimes)]
57#![allow(clippy::too_many_arguments)]
58#![cfg_attr(docsrs, feature(doc_cfg))]
59
60#[cfg(feature = "requests")]
61pub mod basic;
62#[cfg(feature = "requests")]
63pub mod batch;
64#[cfg(feature = "requests")]
65pub mod gdpr;
66mod methods;
67#[cfg(feature = "requests")]
68pub mod public_object;
69#[cfg(feature = "requests")]
70pub mod search;
71#[cfg(test)]
72mod tests;
73pub mod types;
74
75#[cfg(feature = "requests")]
76use std::env;
77
78#[cfg(not(target_arch = "wasm32"))]
79#[cfg(feature = "requests")]
80static APP_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), ".rs/", env!("CARGO_PKG_VERSION"),);
81
82/// Entrypoint for interacting with the API client.
83#[derive(Clone, Debug)]
84#[cfg(feature = "requests")]
85pub struct Client {
86    token: String,
87    base_url: String,
88
89    #[cfg(feature = "retry")]
90    client: reqwest_middleware::ClientWithMiddleware,
91    #[cfg(feature = "retry")]
92    #[cfg(not(target_arch = "wasm32"))]
93    #[allow(dead_code)]
94    client_http1_only: reqwest_middleware::ClientWithMiddleware,
95
96    #[cfg(not(feature = "retry"))]
97    client: reqwest::Client,
98    #[cfg(not(feature = "retry"))]
99    #[cfg(not(target_arch = "wasm32"))]
100    #[allow(dead_code)]
101    client_http1_only: reqwest::Client,
102}
103
104/// A request builder.
105#[cfg(feature = "retry")]
106#[cfg(feature = "requests")]
107pub struct RequestBuilder(pub reqwest_middleware::RequestBuilder);
108#[cfg(not(feature = "retry"))]
109#[cfg(feature = "requests")]
110pub struct RequestBuilder(pub reqwest::RequestBuilder);
111
112#[cfg(feature = "requests")]
113impl Client {
114    /// Create a new Client struct. It takes a type that can convert into
115    /// an &str (`String` or `Vec<u8>` for example). As long as the function is
116    /// given a valid API key your requests will work.
117    /// Also takes reqwest client builders, for customizing the client's behaviour.
118    #[tracing::instrument]
119    #[cfg(not(target_arch = "wasm32"))]
120    pub fn new_from_reqwest<T>(
121        token: T,
122        builder_http: reqwest::ClientBuilder,
123        builder_websocket: reqwest::ClientBuilder,
124    ) -> Self
125    where
126        T: ToString + std::fmt::Debug,
127    {
128        #[cfg(feature = "retry")]
129        {
130            // Retry up to 3 times with increasing intervals between attempts.
131            let retry_policy =
132                reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
133            match (builder_http.build(), builder_websocket.build()) {
134                (Ok(c), Ok(c1)) => {
135                    let client = reqwest_middleware::ClientBuilder::new(c)
136                        // Trace HTTP requests. See the tracing crate to make use of these traces.
137                        .with(reqwest_tracing::TracingMiddleware::default())
138                        // Retry failed requests.
139                        .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
140                            reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
141                            |req: &reqwest::Request| req.try_clone().is_some(),
142                        ))
143                        .build();
144                    let client_http1_only = reqwest_middleware::ClientBuilder::new(c1)
145                        .with(reqwest_tracing::TracingMiddleware::default())
146                        .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
147                            reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
148                            |req: &reqwest::Request| req.try_clone().is_some(),
149                        ))
150                        .build();
151                    Client {
152                        token: token.to_string(),
153                        base_url: "https://api.hubapi.com".to_string(),
154
155                        client,
156                        client_http1_only,
157                    }
158                }
159                (Err(e), _) | (_, Err(e)) => panic!("creating reqwest client failed: {:?}", e),
160            }
161        }
162        #[cfg(not(feature = "retry"))]
163        {
164            match (builder_http.build(), builder_websocket.build()) {
165                (Ok(c), Ok(c1)) => Client {
166                    token: token.to_string(),
167                    base_url: "https://api.hubapi.com".to_string(),
168
169                    client: c,
170                    client_http1_only: c1,
171                },
172                (Err(e), _) | (_, Err(e)) => panic!("creating reqwest client failed: {:?}", e),
173            }
174        }
175    }
176
177    /// Create a new Client struct. It takes a type that can convert into
178    /// an &str (`String` or `Vec<u8>` for example). As long as the function is
179    /// given a valid API key your requests will work.
180    /// Also takes reqwest client builders, for customizing the client's behaviour.
181    #[tracing::instrument]
182    #[cfg(target_arch = "wasm32")]
183    pub fn new_from_reqwest<T>(token: T, builder_http: reqwest::ClientBuilder) -> Self
184    where
185        T: ToString + std::fmt::Debug,
186    {
187        #[cfg(feature = "retry")]
188        {
189            // Retry up to 3 times with increasing intervals between attempts.
190            let retry_policy =
191                reqwest_retry::policies::ExponentialBackoff::builder().build_with_max_retries(3);
192            match builder_http.build() {
193                Ok(c) => {
194                    let client = reqwest_middleware::ClientBuilder::new(c)
195                        // Trace HTTP requests. See the tracing crate to make use of these traces.
196                        .with(reqwest_tracing::TracingMiddleware::default())
197                        // Retry failed requests.
198                        .with(reqwest_conditional_middleware::ConditionalMiddleware::new(
199                            reqwest_retry::RetryTransientMiddleware::new_with_policy(retry_policy),
200                            |req: &reqwest::Request| req.try_clone().is_some(),
201                        ))
202                        .build();
203                    Client {
204                        token: token.to_string(),
205                        base_url: "https://api.hubapi.com".to_string(),
206
207                        client,
208                    }
209                }
210                Err(e) => panic!("creating reqwest client failed: {:?}", e),
211            }
212        }
213        #[cfg(not(feature = "retry"))]
214        {
215            match builder_http.build() {
216                Ok(c) => Client {
217                    token: token.to_string(),
218                    base_url: "https://api.hubapi.com".to_string(),
219
220                    client: c,
221                },
222                Err(e) => panic!("creating reqwest client failed: {:?}", e),
223            }
224        }
225    }
226
227    /// Create a new Client struct. It takes a type that can convert into
228    /// an &str (`String` or `Vec<u8>` for example). As long as the function is
229    /// given a valid API key your requests will work.
230    #[tracing::instrument]
231    pub fn new<T>(token: T) -> Self
232    where
233        T: ToString + std::fmt::Debug,
234    {
235        #[cfg(not(target_arch = "wasm32"))]
236        let client = reqwest::Client::builder()
237            .user_agent(APP_USER_AGENT)
238            // For file conversions we need this to be long.
239            .timeout(std::time::Duration::from_secs(600))
240            .connect_timeout(std::time::Duration::from_secs(60));
241        #[cfg(target_arch = "wasm32")]
242        let client = reqwest::Client::builder();
243        #[cfg(not(target_arch = "wasm32"))]
244        let client_http1 = reqwest::Client::builder()
245            // For file conversions we need this to be long.
246            .user_agent(APP_USER_AGENT)
247            .timeout(std::time::Duration::from_secs(600))
248            .connect_timeout(std::time::Duration::from_secs(60))
249            .http1_only();
250        #[cfg(not(target_arch = "wasm32"))]
251        return Self::new_from_reqwest(token, client, client_http1);
252        #[cfg(target_arch = "wasm32")]
253        Self::new_from_reqwest(token, client)
254    }
255
256    /// Set the base URL for the client to something other than the default: <https://api.hubapi.com>.
257    #[tracing::instrument]
258    pub fn set_base_url<H>(&mut self, base_url: H)
259    where
260        H: Into<String> + std::fmt::Display + std::fmt::Debug,
261    {
262        self.base_url = base_url.to_string().trim_end_matches('/').to_string();
263    }
264
265    /// Create a new Client struct from the environment variable: `ENV_VARIABLE_PREFIX_API_TOKEN`.
266    #[tracing::instrument]
267    pub fn new_from_env() -> Self {
268        let token =
269            env::var("HUBSPOT_CONTACTS_API_TOKEN").expect("must set HUBSPOT_CONTACTS_API_TOKEN");
270        let base_url =
271            env::var("HUBSPOT_CONTACTS_HOST").unwrap_or("https://api.hubapi.com".to_string());
272
273        let mut c = Client::new(token);
274        c.set_base_url(base_url);
275        c
276    }
277
278    /// Create a raw request to our API.
279    #[tracing::instrument]
280    pub async fn request_raw(
281        &self,
282        method: reqwest::Method,
283        uri: &str,
284        body: Option<reqwest::Body>,
285    ) -> anyhow::Result<RequestBuilder> {
286        let u = if uri.starts_with("https://") || uri.starts_with("http://") {
287            uri.to_string()
288        } else {
289            format!("{}/{}", self.base_url, uri.trim_start_matches('/'))
290        };
291
292        let mut req = self.client.request(method, &u);
293
294        // Add in our authentication.
295        req = req.bearer_auth(&self.token);
296
297        // Set the default headers.
298        req = req.header(
299            reqwest::header::ACCEPT,
300            reqwest::header::HeaderValue::from_static("application/json"),
301        );
302        req = req.header(
303            reqwest::header::CONTENT_TYPE,
304            reqwest::header::HeaderValue::from_static("application/json"),
305        );
306
307        if let Some(body) = body {
308            req = req.body(body);
309        }
310
311        Ok(RequestBuilder(req))
312    }
313
314    /// Return a reference to an interface that provides access to Batch operations.
315    pub fn batch(&self) -> batch::Batch {
316        batch::Batch::new(self.clone())
317    }
318
319    /// Return a reference to an interface that provides access to Basic operations.
320    pub fn basic(&self) -> basic::Basic {
321        basic::Basic::new(self.clone())
322    }
323
324    /// Return a reference to an interface that provides access to Public_Object operations.
325    pub fn public_object(&self) -> public_object::PublicObject {
326        public_object::PublicObject::new(self.clone())
327    }
328
329    /// Return a reference to an interface that provides access to GDPR operations.
330    pub fn gdpr(&self) -> gdpr::Gdpr {
331        gdpr::Gdpr::new(self.clone())
332    }
333
334    /// Return a reference to an interface that provides access to Search operations.
335    pub fn search(&self) -> search::Search {
336        search::Search::new(self.clone())
337    }
338}