1use std::{future::Future, pin::Pin, sync::Arc};
2
3use crate::{errors::{ApiError, CrateResult}, utils::{handle_response, handle_response_alt}};
5use reqwest::{IntoUrl, Response, StatusCode, Url, header::HeaderMap, multipart};
6use serde::{Serialize, de::DeserializeOwned};
7
8pub struct RestApiClientBuilder
9{
10 http_client: reqwest::Client,
11 api_base_url: Result<Url, reqwest::Error>,
12 before_request_handler: Option< Pin<Arc< dyn Fn(String) -> Pin<Box< dyn Future<Output = ()> + Send >> + Send + Sync >> >,
13 after_request_handler: Option< Pin<Arc< dyn Fn(&HeaderMap) -> Pin<Box< dyn Future<Output = ()> + Send >> + Send + Sync >> >,
14 handle_api_error: Option< Arc<dyn Fn(StatusCode, Option<String>) -> ApiError + Send + Sync> >
15}
16impl RestApiClientBuilder {
17 pub fn new<T: IntoUrl>(http_client: reqwest::Client, api_base_url: T) -> Self {
18 Self{
19 http_client: http_client,
20 api_base_url: api_base_url.into_url(),
21 before_request_handler: None,
22 after_request_handler: None,
23 handle_api_error: None,
24 }
25 }
26 pub fn on_api_error<Func>(mut self, handler: Func) -> Self
27 where
28 Func: Fn(StatusCode, Option<String>) -> ApiError + Send + Sync + 'static
29 {
30 self.handle_api_error = Some(Arc::new( handler));
31 self
32 }
33 pub fn before_request<Fut, Func>(mut self, handler: Func) -> Self
34 where
35 Fut: Future<Output = ()> + Send + 'static,
36 Func: Fn(String) -> Fut + Send + Sync + 'static
37 {
38 self.before_request_handler = Some(Arc::pin(move |headers| Box::pin(handler(headers))));
39 self
40 }
41 pub fn after_request<Fut, Func>(mut self, handler: Func) -> Self
42 where
43 Fut: Future<Output = ()> + Send + 'static,
44 Func: Fn(&HeaderMap) -> Fut + Send + Sync + 'static
45 {
46 self.after_request_handler = Some(Arc::pin(move |headers| Box::pin(handler(headers))));
47 self
48 }
49 pub fn build(self) -> CrateResult<RestApiClient> {
50 Ok(
51 RestApiClient{
52 http_client: self.http_client,
53 api_base_url: self.api_base_url?.to_string().strip_suffix("/").unwrap().to_string(),
54 before_request_handler: self.before_request_handler,
55 after_request_handler: self.after_request_handler,
56 handle_api_error: self.handle_api_error
57 }
58 )
59 }
60}
61
62#[derive(Clone)]
63pub struct RestApiClient
64{
65 http_client: reqwest::Client,
66 api_base_url: String,
67 before_request_handler: Option< Pin<Arc< dyn Fn(String) -> Pin<Box< dyn Future<Output = ()> + Send >> + Send + Sync >> >,
68 after_request_handler: Option< Pin<Arc< dyn Fn(&HeaderMap) -> Pin<Box< dyn Future<Output = ()> + Send >> + Send + Sync >> >,
69 handle_api_error: Option< Arc<dyn Fn(StatusCode, Option<String>) -> ApiError + Send + Sync> >
70}
71impl RestApiClient
72{
73 pub async fn get<ResponseDataType>(&self, path: &str) -> CrateResult<(ResponseDataType, HeaderMap)>
74 where
75 ResponseDataType: DeserializeOwned
76 {
77 let url = self.api_base_url.clone() + path;
78 let response = run_request(url.clone(), &self.before_request_handler, || async {self.http_client.get(url.clone()).send().await}, &self.after_request_handler).await?;
79 let data: CrateResult<(ResponseDataType, HeaderMap)> = handle_response(response, &self.handle_api_error).await;
80 return data
81 }
82 pub async fn post<RequestDataType, ResponseDataType>(&self, request_data: RequestDataType, path: &str) -> CrateResult<(ResponseDataType, HeaderMap)>
83 where
84 RequestDataType: Serialize,
85 ResponseDataType: DeserializeOwned
86 {
87 let url = self.api_base_url.clone() + path;
88 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.post(url.clone()).json(&request_data).send().await }, &self.after_request_handler).await?;
89 let data: CrateResult<(ResponseDataType, HeaderMap)> = handle_response(response, &self.handle_api_error).await;
90 return data
91 }
92 pub async fn patch<RequestDataType, ResponseDataType>(&self, request_data: RequestDataType, path: &str) -> CrateResult<(ResponseDataType, HeaderMap)>
93 where
94 RequestDataType: Serialize,
95 ResponseDataType: DeserializeOwned
96 {
97 let url = self.api_base_url.to_string() + path;
98 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.patch(url.clone()).json(&request_data).send().await }, &self.after_request_handler).await?;
99 let data: CrateResult<(ResponseDataType, HeaderMap)> = handle_response(response, &self.handle_api_error).await;
100 return data
101 }
102 pub async fn put<RequestDataType, ResponseDataType>(&self, request_data: RequestDataType, path: &str) -> CrateResult<(ResponseDataType, HeaderMap)>
103 where
104 RequestDataType: Serialize,
105 ResponseDataType: DeserializeOwned
106 {
107 let url = self.api_base_url.to_string() + path;
108 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.put(url.clone()).json(&request_data).send().await }, &self.after_request_handler).await?;
109 let data: CrateResult<(ResponseDataType, HeaderMap)> = handle_response(response, &self.handle_api_error).await;
110 return data
111 }
112 pub async fn delete<ResponseDataType>(&self, path: &str) -> CrateResult<(ResponseDataType, HeaderMap)>
113 where
114 ResponseDataType: DeserializeOwned
115 {
116 let url = self.api_base_url.to_string() + path;
117 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.delete(url.clone()).send().await }, &self.after_request_handler).await?;
118 let data: CrateResult<(ResponseDataType, HeaderMap)> = handle_response(response, &self.handle_api_error).await;
119 return data
120 }
121 pub async fn post_alt<RequestDataType>(&self, request_data: RequestDataType, path: &str) -> CrateResult<HeaderMap>
132 where
133 RequestDataType: Serialize,
134 {
135 let url = self.api_base_url.to_string() + path;
136 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.post(url.clone()).json(&request_data).send().await }, &self.after_request_handler).await?;
137 let data: CrateResult<HeaderMap> = handle_response_alt(response, &self.handle_api_error).await;
138 return data
139 }
140 pub async fn patch_alt<RequestDataType>(&self, request_data: RequestDataType, path: &str) -> CrateResult<HeaderMap>
141 where
142 RequestDataType: Serialize,
143 {
144 let url = self.api_base_url.to_string() + path;
145 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.patch(url.clone()).json(&request_data).send().await }, &self.after_request_handler).await?;
146 let data: CrateResult<HeaderMap> = handle_response_alt(response, &self.handle_api_error).await;
147 return data
148 }
149 pub async fn put_alt<RequestDataType>(&self, request_data: RequestDataType, path: &str) -> CrateResult<HeaderMap>
150 where
151 RequestDataType: Serialize,
152 {
153 let url = self.api_base_url.to_string() + path;
154 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.put(url.clone()).json(&request_data).send().await }, &self.after_request_handler).await?;
155 let data: CrateResult<HeaderMap> = handle_response_alt(response, &self.handle_api_error).await;
156 return data
157 }
158 pub async fn delete_alt(&self, path: &str) -> CrateResult<HeaderMap> {
159 let url = self.api_base_url.to_string() + path;
160 let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.delete(url.clone()).send().await }, &self.after_request_handler).await?;
161 let data: CrateResult<HeaderMap> = handle_response_alt(response, &self.handle_api_error).await;
162 return data
163 }
164
165 pub async fn post_multipart_alt(&self, form: multipart::Form, path: &str) -> CrateResult<HeaderMap>
166 where
167 {
168 let url = self.api_base_url.to_string() + path;
169 if let Some(handler) = self.before_request_handler.clone() {
171 handler(url.clone()).await;
172 }
173 let response = self.http_client.post(url.clone()).multipart(form).send().await?;
174 if let Some(handler) = self.after_request_handler.clone() {
175 handler(response.headers()).await;
176 }
177 let data: CrateResult<HeaderMap> = handle_response_alt(response, &self.handle_api_error).await;
178 return data
179 }
180}
181
182async fn run_request<BFtr, BFn, RFtr, RFn, AFtr, AFn>(url: String, before_handler: &Option<Pin<Arc<BFn>> >, request: RFn, after_handler: &Option<Pin<Arc<AFn>>>) -> CrateResult<Response>
183where
184 BFtr: Future<Output = ()>,
185 BFn: Fn(String) -> BFtr + ?Sized,
186 RFtr: Future<Output = Result<Response, reqwest::Error>>,
187 RFn: Fn() -> RFtr,
188 AFtr: Future<Output = ()>,
189 AFn: Fn(&HeaderMap) -> AFtr + ?Sized
190{
191 if let Some(handler) = before_handler {
192 handler(url).await;
193 }
194 let response = request().await?;
195 if let Some(handler) = after_handler {
196 handler(response.headers()).await;
197 }
198 return Ok(response)
199}