api_client_framework/
async_client.rs1use super::endpoint::Endpoint;
2use crate::Error;
3use reqwest::{header::HeaderMap, Response, StatusCode};
4use reqwest_middleware::{ClientBuilder, Middleware};
5use serde::Deserialize;
6use std::{sync::Arc, time::Duration};
7
8#[derive(Clone)]
9pub struct HttpApiClientConfig {
10 pub http_timeout: Duration,
13 pub default_headers: HeaderMap,
15 pub middlewares: Vec<Arc<dyn Middleware>>,
17}
18
19impl Default for HttpApiClientConfig {
20 fn default() -> Self {
21 Self {
22 http_timeout: Duration::from_secs(30),
23 default_headers: HeaderMap::default(),
24 middlewares: Vec::new(),
25 }
26 }
27}
28
29#[derive(Clone)]
30pub struct HttpApiClient {
31 base_url: url::Url,
32 http_client: reqwest_middleware::ClientWithMiddleware,
33}
34
35impl HttpApiClient {
36 pub fn new(base_url: url::Url, config: HttpApiClientConfig) -> Result<Self, Error> {
37 let reqwest_client = reqwest::Client::builder()
38 .default_headers(config.default_headers)
39 .timeout(config.http_timeout)
40 .build()?;
41 let mut client_builder = ClientBuilder::new(reqwest_client);
42 for middleware in config.middlewares {
43 client_builder = client_builder.with_arc(middleware);
44 }
45 let client = client_builder.build();
46
47 Ok(Self {
48 base_url,
49 http_client: client,
50 })
51 }
52
53 pub async fn request<EndpointType: Endpoint>(
55 &self,
56 endpoint: &EndpointType,
57 ) -> Result<<EndpointType as Endpoint>::Response, Error> {
58 let mut request = self
60 .http_client
61 .request(endpoint.method(), endpoint.url(&self.base_url));
62
63 if let Some(body) = endpoint.body() {
64 request = request.body(body);
65 request = request.header(
66 reqwest::header::CONTENT_TYPE,
67 endpoint.content_type().as_ref(),
68 );
69 }
70
71 if let Some(headers) = endpoint.headers() {
72 request = request.headers(headers);
73 }
74
75 let response = request.send().await?;
76 process_api_response(response).await
77 }
78}
79
80async fn process_api_response<T: for<'a> Deserialize<'a>>(response: Response) -> Result<T, Error> {
81 let status = response.status();
82 match status {
83 status if status.is_success() => (),
84 StatusCode::NOT_FOUND => return Err(Error::NotFound),
85 status => {
86 return Err(Error::InvalidStatusCode {
87 status_code: status,
88 message: response.text().await?,
89 })
90 }
91 }
92
93 let raw_value = response.bytes().await?;
94 let deserializer = &mut serde_json::Deserializer::from_slice(raw_value.as_ref());
95 let value: T = serde_path_to_error::deserialize(deserializer)?;
96 Ok(value)
97}