rest_api_utils/
clients.rs

1use std::{future::Future, pin::Pin, sync::Arc};
2
3// use crate::utils::handle_response;
4use 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_multipart<ResponseDataType>(&self, form: multipart::Form, path: &str) -> CrateResult<ResponseDataType>
122    // where
123    //     ResponseDataType: DeserializeOwned
124    // {
125    //     let url = self.api_base_url.to_string() + path;
126    //     let response = run_request(url.clone(), &self.before_request_handler, || async { self.http_client.post(url.clone()).multipart(form).send().await }, &self.after_request_handler).await.unwrap();
127    //     let data: CrateResult<(ResponseDataType, HeaderMap)> = handle_response(response, &self.handle_api_error).await;
128    //     return data
129    // }
130    
131    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        // let response = self.http_client.post(url).multipart(form).send().await?;
170        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}