Skip to main content

highlevel_api/http/
mod.rs

1use reqwest::{Client, Response};
2use serde::{de::DeserializeOwned, Serialize};
3use tokio::sync::RwLock;
4use crate::{
5    config::HighLevelConfig,
6    error::{Error, Result},
7};
8
9pub struct HttpClient {
10    inner: Client,
11    pub base_url: String,
12    pub api_version: String,
13    token: RwLock<Option<String>>,
14}
15
16impl HttpClient {
17    pub fn new(config: &HighLevelConfig) -> Self {
18        Self {
19            inner: Client::new(),
20            base_url: config.base_url.clone(),
21            api_version: config.api_version.clone(),
22            token: RwLock::new(None),
23        }
24    }
25
26    pub async fn set_token(&self, token: String) {
27        *self.token.write().await = Some(token);
28    }
29
30    pub async fn get_token(&self) -> Option<String> {
31        self.token.read().await.clone()
32    }
33
34    fn url(&self, path: &str) -> String {
35        format!("{}{}", self.base_url, path)
36    }
37
38    async fn handle_response<T: DeserializeOwned>(&self, resp: Response) -> Result<T> {
39        let status = resp.status();
40        if status.is_success() {
41            Ok(resp.json::<T>().await?)
42        } else {
43            let code = status.as_u16();
44            let body = resp.text().await.unwrap_or_default();
45            let message = serde_json::from_str::<serde_json::Value>(&body)
46                .ok()
47                .and_then(|v| {
48                    v.get("message")
49                        .and_then(|m| m.as_str())
50                        .map(|s| s.to_string())
51                })
52                .unwrap_or(body);
53            Err(Error::Api { status: code, message })
54        }
55    }
56
57    async fn handle_no_content(&self, resp: Response) -> Result<()> {
58        let status = resp.status();
59        if status.is_success() {
60            Ok(())
61        } else {
62            let code = status.as_u16();
63            let message = resp.text().await.unwrap_or_else(|_| status.to_string());
64            Err(Error::Api { status: code, message })
65        }
66    }
67
68    pub async fn get<T: DeserializeOwned>(&self, path: &str) -> Result<T> {
69        let token = self.token.read().await.clone();
70        let mut req = self
71            .inner
72            .get(self.url(path))
73            .header("Version", &self.api_version)
74            .header("Content-Type", "application/json");
75        if let Some(t) = token {
76            req = req.bearer_auth(t);
77        }
78        self.handle_response(req.send().await?).await
79    }
80
81    pub async fn get_with_query<T: DeserializeOwned, Q: Serialize + ?Sized>(
82        &self,
83        path: &str,
84        query: &Q,
85    ) -> Result<T> {
86        let token = self.token.read().await.clone();
87        let mut req = self
88            .inner
89            .get(self.url(path))
90            .header("Version", &self.api_version)
91            .header("Content-Type", "application/json")
92            .query(query);
93        if let Some(t) = token {
94            req = req.bearer_auth(t);
95        }
96        self.handle_response(req.send().await?).await
97    }
98
99    pub async fn post<T: DeserializeOwned, B: Serialize>(&self, path: &str, body: &B) -> Result<T> {
100        let token = self.token.read().await.clone();
101        let mut req = self
102            .inner
103            .post(self.url(path))
104            .header("Version", &self.api_version)
105            .json(body);
106        if let Some(t) = token {
107            req = req.bearer_auth(t);
108        }
109        self.handle_response(req.send().await?).await
110    }
111
112    pub async fn put<T: DeserializeOwned, B: Serialize>(&self, path: &str, body: &B) -> Result<T> {
113        let token = self.token.read().await.clone();
114        let mut req = self
115            .inner
116            .put(self.url(path))
117            .header("Version", &self.api_version)
118            .json(body);
119        if let Some(t) = token {
120            req = req.bearer_auth(t);
121        }
122        self.handle_response(req.send().await?).await
123    }
124
125    pub async fn patch<T: DeserializeOwned, B: Serialize>(&self, path: &str, body: &B) -> Result<T> {
126        let token = self.token.read().await.clone();
127        let mut req = self
128            .inner
129            .patch(self.url(path))
130            .header("Version", &self.api_version)
131            .json(body);
132        if let Some(t) = token {
133            req = req.bearer_auth(t);
134        }
135        self.handle_response(req.send().await?).await
136    }
137
138    pub async fn delete<T: DeserializeOwned>(&self, path: &str) -> Result<T> {
139        let token = self.token.read().await.clone();
140        let mut req = self
141            .inner
142            .delete(self.url(path))
143            .header("Version", &self.api_version);
144        if let Some(t) = token {
145            req = req.bearer_auth(t);
146        }
147        self.handle_response(req.send().await?).await
148    }
149
150    pub async fn delete_with_body<T: DeserializeOwned, B: Serialize>(
151        &self,
152        path: &str,
153        body: &B,
154    ) -> Result<T> {
155        let token = self.token.read().await.clone();
156        let mut req = self
157            .inner
158            .delete(self.url(path))
159            .header("Version", &self.api_version)
160            .json(body);
161        if let Some(t) = token {
162            req = req.bearer_auth(t);
163        }
164        self.handle_response(req.send().await?).await
165    }
166
167    pub async fn delete_no_content(&self, path: &str) -> Result<()> {
168        let token = self.token.read().await.clone();
169        let mut req = self
170            .inner
171            .delete(self.url(path))
172            .header("Version", &self.api_version);
173        if let Some(t) = token {
174            req = req.bearer_auth(t);
175        }
176        self.handle_no_content(req.send().await?).await
177    }
178}