#[cfg(feature = "blocking")]
use crate::blocking::client::Client as BlockingClient;
use crate::{
client::Client,
enums::{RequestMethod, RequestType, ResponseType},
errors::ClientError,
};
use async_trait::async_trait;
use bytes::Bytes;
use http::{Request, Response};
use serde::{de::DeserializeOwned, Serialize};
use serde_json::Value;
pub trait Wrapper: DeserializeOwned {
type Value;
}
#[async_trait]
pub trait Endpoint: Send + Sync + Serialize + Sized {
type Response: DeserializeOwned;
const REQUEST_BODY_TYPE: RequestType;
const RESPONSE_BODY_TYPE: ResponseType;
fn path(&self) -> String;
fn method(&self) -> RequestMethod;
fn query(&self) -> Vec<(String, Value)> {
Vec::new()
}
fn data(&self) -> Option<Bytes> {
None
}
async fn exec(&self, client: &impl Client) -> Result<Option<Self::Response>, ClientError> {
log::info!("Executing endpoint");
let req = build(client.base(), self)?;
let resp = exec(client, req).await?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
async fn exec_mut(
&self,
client: &impl Client,
middle: &impl MiddleWare,
) -> Result<Option<Self::Response>, ClientError> {
log::info!("Executing endpoint");
let req = build_mut(client.base(), self, middle)?;
let resp = exec_mut(client, self, req, middle).await?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
async fn exec_wrap<W>(&self, client: &impl Client) -> Result<Option<W>, ClientError>
where
W: Wrapper<Value = Self::Response>,
{
log::info!("Executing endpoint");
let req = build(client.base(), self)?;
let resp = exec(client, req).await?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
async fn exec_wrap_mut<W>(
&self,
client: &impl Client,
middle: &impl MiddleWare,
) -> Result<Option<W>, ClientError>
where
W: Wrapper<Value = Self::Response>,
{
log::info!("Executing endpoint");
let req = build_mut(client.base(), self, middle)?;
let resp = exec_mut(client, self, req, middle).await?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
async fn exec_raw(&self, client: &impl Client) -> Result<Bytes, ClientError> {
log::info!("Executing endpoint");
let req = build(client.base(), self)?;
let resp = exec(client, req).await?;
Ok(resp.body().clone())
}
async fn exec_raw_mut(
&self,
client: &impl Client,
middle: &impl MiddleWare,
) -> Result<Bytes, ClientError> {
log::info!("Executing endpoint");
let req = build_mut(client.base(), self, middle)?;
let resp = exec_mut(client, self, req, middle).await?;
Ok(resp.body().clone())
}
#[cfg(feature = "blocking")]
fn exec_block(
&self,
client: &impl BlockingClient,
) -> Result<Option<Self::Response>, ClientError> {
log::info!("Executing endpoint");
let req = build(client.base(), self)?;
let resp = exec_block(client, req)?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
#[cfg(feature = "blocking")]
fn exec_mut_block(
&self,
client: &impl BlockingClient,
middle: &impl MiddleWare,
) -> Result<Option<Self::Response>, ClientError> {
log::info!("Executing endpoint");
let req = build_mut(client.base(), self, middle)?;
let resp = exec_mut_block(client, self, req, middle)?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
#[cfg(feature = "blocking")]
fn exec_wrap_block<W>(&self, client: &impl BlockingClient) -> Result<Option<W>, ClientError>
where
W: Wrapper<Value = Self::Response>,
{
log::info!("Executing endpoint");
let req = build(client.base(), self)?;
let resp = exec_block(client, req)?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
#[cfg(feature = "blocking")]
fn exec_wrap_mut_block<W>(
&self,
client: &impl BlockingClient,
middle: &impl MiddleWare,
) -> Result<Option<W>, ClientError>
where
W: Wrapper<Value = Self::Response>,
{
log::info!("Executing endpoint");
let req = build_mut(client.base(), self, middle)?;
let resp = exec_mut_block(client, self, req, middle)?;
crate::http::parse(Self::RESPONSE_BODY_TYPE, resp.body())
}
#[cfg(feature = "blocking")]
fn exec_raw_block(&self, client: &impl BlockingClient) -> Result<Bytes, ClientError> {
log::info!("Executing endpoint");
let req = build(client.base(), self)?;
let resp = exec_block(client, req)?;
Ok(resp.body().clone())
}
#[cfg(feature = "blocking")]
fn exec_raw_mut_block(
&self,
client: &impl BlockingClient,
middle: &impl MiddleWare,
) -> Result<Bytes, ClientError> {
log::info!("Executing endpoint");
let req = build_mut(client.base(), self, middle)?;
let resp = exec_mut_block(client, self, req, middle)?;
Ok(resp.body().clone())
}
}
pub trait MiddleWare: Sync + Send {
fn request<E: Endpoint>(
&self,
endpoint: &E,
req: &mut Request<Bytes>,
) -> Result<(), ClientError>;
fn response<E: Endpoint>(
&self,
endpoint: &E,
resp: &mut Response<Bytes>,
) -> Result<(), ClientError>;
}
fn build<E: Endpoint>(base: &str, endpoint: &E) -> Result<Request<Bytes>, ClientError> {
crate::http::build_request(
base,
endpoint.path().as_str(),
endpoint.method(),
endpoint.query(),
crate::http::build_body(endpoint, E::REQUEST_BODY_TYPE, endpoint.data())?,
)
}
fn build_mut<E: Endpoint>(
base: &str,
endpoint: &E,
middle: &impl MiddleWare,
) -> Result<Request<Bytes>, ClientError> {
let mut req = crate::http::build_request(
base,
endpoint.path().as_str(),
endpoint.method(),
endpoint.query(),
crate::http::build_body(endpoint, E::REQUEST_BODY_TYPE, endpoint.data())?,
)?;
middle.request(endpoint, &mut req)?;
Ok(req)
}
async fn exec(client: &impl Client, req: Request<Bytes>) -> Result<Response<Bytes>, ClientError> {
client.execute(req).await
}
async fn exec_mut(
client: &impl Client,
endpoint: &impl Endpoint,
req: Request<Bytes>,
middle: &impl MiddleWare,
) -> Result<Response<Bytes>, ClientError> {
let mut resp = client.execute(req).await?;
middle.response(endpoint, &mut resp)?;
Ok(resp)
}
#[cfg(feature = "blocking")]
fn exec_block(
client: &impl BlockingClient,
req: Request<Bytes>,
) -> Result<Response<Bytes>, ClientError> {
client.execute(req)
}
#[cfg(feature = "blocking")]
fn exec_mut_block(
client: &impl BlockingClient,
endpoint: &impl Endpoint,
req: Request<Bytes>,
middle: &impl MiddleWare,
) -> Result<Response<Bytes>, ClientError> {
let mut resp = client.execute(req)?;
middle.response(endpoint, &mut resp)?;
Ok(resp)
}