rusty_box/client/
http_client.rs1use std::{collections::HashMap, time::Duration};
5
6use reqwest::{Method, RequestBuilder};
7use serde_json::Value;
8
9use crate::client::client_error_model::BoxAPIErrorResponse;
10
11use super::client_error::BoxAPIError;
12
13pub type Headers = HashMap<String, String>;
15pub type Query<'a> = HashMap<&'a str, &'a str>;
17pub type Form<'a> = HashMap<&'a str, &'a str>;
19
20#[derive(Debug, Clone)]
21pub struct HttpClient {
22 client: reqwest::Client,
24}
25
26impl Default for HttpClient {
27 fn default() -> Self {
28 let client = reqwest::ClientBuilder::new()
29 .timeout(Duration::from_secs(10))
30 .build()
31 .unwrap();
33 Self { client }
34 }
35}
36
37impl HttpClient {
38 async fn request<D>(
39 &self,
40 method: Method,
41 url: &str,
42 headers: Option<&Headers>,
43 add_data: D,
44 ) -> Result<String, BoxAPIError>
45 where
46 D: Fn(RequestBuilder) -> RequestBuilder,
47 {
48 let mut request = self.client.request(method.clone(), url);
49
50 if let Some(headers) = headers {
52 let headers = headers.try_into().unwrap();
59
60 request = request.headers(headers);
61 }
62
63 request = add_data(request);
65
66 log::info!("Making request {:?}", request);
68 let response = request.send().await?;
69 let status = response.status();
70 let resp_text = response.text().await?;
71
72 if status.is_success() {
74 Ok(resp_text)
75 } else {
76 let resp_error = serde_json::from_str::<BoxAPIErrorResponse>(&resp_text)?;
77 Err(BoxAPIError::ResponseError(resp_error))
78 }
79 }
80}
81
82impl HttpClient {
83 #[inline]
86 pub async fn get(
87 &self,
88 url: &str,
89 headers: Option<&Headers>,
90 query: &Query<'_>,
91 ) -> Result<String, BoxAPIError> {
92 self.request(Method::GET, url, headers, |req| req.query(query))
93 .await
94 }
95
96 #[inline]
97 pub async fn post(
98 &self,
99 url: &str,
100 headers: Option<&Headers>,
101 query: Option<&Query<'_>>,
102 payload: &Value,
103 ) -> Result<String, BoxAPIError> {
104 self.request(Method::POST, url, headers, |req| {
105 req.query(&query).json(payload)
106 })
107 .await
108 }
109
110 #[inline]
111 pub async fn post_form(
112 &self,
113 url: &str,
114 headers: Option<&Headers>,
115 payload: &Form<'_>,
116 ) -> Result<String, BoxAPIError> {
117 self.request(Method::POST, url, headers, |req| req.form(payload))
118 .await
119 }
120
121 #[inline]
122 pub async fn put(
123 &self,
124 url: &str,
125 headers: Option<&Headers>,
126 query: Option<&Query<'_>>,
127 payload: &Value,
128 ) -> Result<String, BoxAPIError> {
129 self.request(Method::PUT, url, headers, |req| {
130 req.query(&query).json(payload)
131 })
132 .await
133 }
134
135 #[inline]
136 pub async fn delete(
137 &self,
138 url: &str,
139 headers: Option<&Headers>,
140 payload: &Value,
141 ) -> Result<String, BoxAPIError> {
142 self.request(Method::DELETE, url, headers, |req| req.json(payload))
143 .await
144 }
145
146 }