reqwest-traits 0.2.0

Traits for reqwest to allow injecting a custom http client like reqwest_middleware::ClientWithMiddleware
Documentation
use async_trait::async_trait;
use reqwest::header::{HeaderName, HeaderValue};
use reqwest::{IntoUrl, Method, Request, Response};

use crate::{Client, RequestBuilder};

#[async_trait]
impl RequestBuilder for reqwest_middleware::RequestBuilder {
    type Error = reqwest_middleware::Error;

    fn header<K, V>(self, key: K, value: V) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
        HeaderValue: TryFrom<V>,
        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
    {
        Self::header(self, key, value)
    }

    fn headers(self, headers: reqwest::header::HeaderMap) -> Self {
        Self::headers(self, headers)
    }

    fn basic_auth<U, P>(self, username: U, password: Option<P>) -> Self
    where
        U: std::fmt::Display,
        P: std::fmt::Display,
    {
        Self::basic_auth(self, username, password)
    }

    fn bearer_auth<T>(self, token: T) -> Self
    where
        T: std::fmt::Display,
    {
        Self::bearer_auth(self, token)
    }

    fn body<T: Into<reqwest::Body>>(self, body: T) -> Self {
        Self::body(self, body)
    }

    fn json<T: serde::Serialize + ?Sized>(self, json: &T) -> Self {
        Self::json(self, json)
    }

    fn timeout(self, timeout: std::time::Duration) -> Self {
        Self::timeout(self, timeout)
    }

    fn query<T: serde::Serialize + ?Sized>(self, query: &T) -> Self {
        Self::query(self, query)
    }

    fn version(self, version: http::Version) -> Self {
        Self::version(self, version)
    }

    fn build(self) -> Result<Request, reqwest::Error> {
        Self::build(self)
    }

    async fn send(self) -> Result<reqwest::Response, Self::Error> {
        Self::send(self).await
    }
}

#[async_trait]
impl Client for reqwest_middleware::ClientWithMiddleware {
    type RequestBuilder = reqwest_middleware::RequestBuilder;
    type Error = reqwest_middleware::Error;

    fn get<U: IntoUrl>(&self, url: U) -> Self::RequestBuilder {
        Self::get(self, url)
    }

    fn post<U: IntoUrl>(&self, url: U) -> Self::RequestBuilder {
        Self::post(self, url)
    }

    fn put<U: IntoUrl>(&self, url: U) -> Self::RequestBuilder {
        Self::put(self, url)
    }

    fn patch<U: IntoUrl>(&self, url: U) -> Self::RequestBuilder {
        Self::patch(self, url)
    }

    fn delete<U: IntoUrl>(&self, url: U) -> Self::RequestBuilder {
        Self::delete(self, url)
    }

    fn head<U: IntoUrl>(&self, url: U) -> Self::RequestBuilder {
        Self::head(self, url)
    }

    fn request<U: IntoUrl>(&self, method: Method, url: U) -> Self::RequestBuilder {
        Self::request(self, method, url)
    }

    async fn execute(&self, request: Request) -> Result<Response, Self::Error> {
        Self::execute(self, request).await
    }
}

#[cfg(test)]
mod tests {
    use reqwest::StatusCode;
    use tokio;

    use super::*;

    struct MyClient<C: Client> {
        http: C,
    }

    #[tokio::test]
    async fn get_with_reqwest() {
        let client = MyClient {
            http: reqwest_middleware::ClientBuilder::new(reqwest::Client::new()).build(),
        };
        let request = client.http.get("https://www.rust-lang.org");
        let response = request.send().await.unwrap();
        assert_eq!(response.status(), StatusCode::OK);
    }
}