use crate::http::{
headers::{HeaderName, ToHeaderValues},
Body, Method, Mime, Url,
};
use crate::{Client, Error, Request, Response, Result};
use futures_util::future::BoxFuture;
use serde::Serialize;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
pub struct RequestBuilder {
req: Option<Request>,
client: Option<Client>,
fut: Option<BoxFuture<'static, Result<Response>>>,
}
impl RequestBuilder {
pub fn new(method: Method, url: Url) -> Self {
Self {
req: Some(Request::new(method, url)),
client: None,
fut: None,
}
}
pub(crate) fn with_client(mut self, client: Client) -> Self {
self.client = Some(client);
self
}
pub fn header(mut self, key: impl Into<HeaderName>, value: impl ToHeaderValues) -> Self {
self.req.as_mut().unwrap().insert_header(key, value);
self
}
pub fn content_type(mut self, content_type: impl Into<Mime>) -> Self {
self.req
.as_mut()
.unwrap()
.set_content_type(content_type.into());
self
}
pub fn body(mut self, body: impl Into<Body>) -> Self {
self.req.as_mut().unwrap().set_body(body);
self
}
pub fn query(mut self, query: &impl Serialize) -> std::result::Result<Self, Error> {
self.req.as_mut().unwrap().set_query(query)?;
Ok(self)
}
pub async fn recv_bytes(self) -> Result<Vec<u8>> {
let mut res = self.send().await?;
Ok(res.body_bytes().await?)
}
pub async fn recv_string(self) -> Result<String> {
let mut res = self.send().await?;
Ok(res.body_string().await?)
}
pub async fn recv_json<T: serde::de::DeserializeOwned>(self) -> Result<T> {
let mut res = self.send().await?;
Ok(res.body_json::<T>().await?)
}
pub async fn recv_form<T: serde::de::DeserializeOwned>(self) -> Result<T> {
let mut res = self.send().await?;
Ok(res.body_form::<T>().await?)
}
pub fn build(self) -> Request {
self.req.unwrap()
}
pub async fn send(mut self) -> Result<Response> {
self.client
.take()
.unwrap_or_else(Client::new_shared_or_panic)
.send(self.build())
.await
}
}
impl fmt::Debug for RequestBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.req, f)
}
}
impl Future for RequestBuilder {
type Output = Result<Response>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.fut.is_none() {
let req = self.req.take().unwrap();
let client = self
.client
.take()
.unwrap_or_else(Client::new_shared_or_panic);
self.fut = Some(Box::pin(async move { client.send(req).await }))
}
self.fut.as_mut().unwrap().as_mut().poll(cx)
}
}
impl Into<Request> for RequestBuilder {
fn into(self) -> Request {
self.build()
}
}