highlevel_api/http/
mod.rs1use 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}