use super::interface::ApiInterface;
use anyhow::{Context, Result};
use reqwest::{
Method,
header::{HeaderName, HeaderValue},
};
use reqwest_middleware::ClientWithMiddleware;
use serde::{Serialize, de::DeserializeOwned};
use std::collections::HashMap;
use std::fmt::Display;
pub struct ApiClient<T: ApiInterface> {
pub(super) interface: T,
pub(super) http_client: ClientWithMiddleware,
}
unsafe impl<T: ApiInterface> Send for ApiClient<T> {}
unsafe impl<T: ApiInterface> Sync for ApiClient<T> {}
impl<T: ApiInterface> ApiClient<T> {
pub async fn request<
R: DeserializeOwned,
E: Display,
HK: Into<HeaderName>,
HV: Into<HeaderValue>,
P: Serialize,
B: Serialize,
>(
&self,
endpoint: E,
method: Method,
headers: HashMap<HK, HV>,
params: Option<P>,
body: Option<B>,
) -> Result<R> {
let request = self.interface.build_request(
self.http_client.clone(),
endpoint,
method,
headers,
params,
body,
)?;
trace!("Sending request for json response: {request:?}");
self.http_client
.execute(request)
.await
.context("(JSON) Cannot send request")?
.json()
.await
.context("(JSON) Cannot decode request")
}
pub async fn string_request<
E: Display,
HK: Into<HeaderName>,
HV: Into<HeaderValue>,
P: Serialize,
B: Serialize,
>(
&self,
endpoint: E,
method: Method,
headers: HashMap<HK, HV>,
params: Option<P>,
body: Option<B>,
) -> Result<String> {
let request = self.interface.build_request(
self.http_client.clone(),
endpoint,
method,
headers,
params,
body,
)?;
trace!("Sending request for text response: {request:?}");
let response = self
.http_client
.execute(request)
.await
.context("(TEXT) Cannot send request")?;
trace!("Response for text request: {response:?}");
response
.text()
.await
.context("(TEXT) Cannot decode request")
}
pub async fn simple_get<R: DeserializeOwned, E: Display>(&self, endpoint: E) -> Result<R> {
self.request(
endpoint,
Method::GET,
HashMap::<HeaderName, HeaderValue>::new(),
None::<()>,
None::<()>,
)
.await
}
pub async fn get_params<R: DeserializeOwned, E: Display, P: Serialize>(
&self,
endpoint: E,
params: P,
) -> Result<R> {
self.request(
endpoint,
Method::GET,
HashMap::<HeaderName, HeaderValue>::new(),
Some(params),
None::<()>,
)
.await
}
pub async fn simple_post<R: DeserializeOwned, E: Display, B: Serialize>(
&self,
endpoint: E,
body: B,
) -> Result<R> {
self.request(
endpoint,
Method::POST,
HashMap::<HeaderName, HeaderValue>::new(),
None::<()>,
Some(body),
)
.await
}
pub async fn post_params<R: DeserializeOwned, E: Display, P: Serialize, B: Serialize>(
&self,
endpoint: E,
params: P,
body: B,
) -> Result<R> {
self.request(
endpoint,
Method::POST,
HashMap::<HeaderName, HeaderValue>::new(),
Some(params),
Some(body),
)
.await
}
}