Skip to main content

agentai_core/http/
reqwest.rs

1//! [`HttpClient`] implemented with `reqwest`.
2
3use super::{HttpClient, HttpError, HttpRequest, HttpResponse, Method};
4use async_trait::async_trait;
5
6/// [`HttpClient`] on top of `reqwest`.
7#[derive(Debug, Clone)]
8pub struct ReqwestClient {
9    client: reqwest::Client,
10}
11
12impl ReqwestClient {
13    /// Creates a client with the default `reqwest` settings.
14    ///
15    /// It first installs the crypto provider chosen by the TLS features, see
16    /// [`install_crypto_provider`](crate::tls::install_crypto_provider).
17    pub fn new() -> Self {
18        crate::tls::install_crypto_provider();
19        Self {
20            client: reqwest::Client::new(),
21        }
22    }
23
24    /// Uses a configured `reqwest` client (timeouts, proxy, ...).
25    pub fn from_client(client: reqwest::Client) -> Self {
26        Self { client }
27    }
28}
29
30impl Default for ReqwestClient {
31    fn default() -> Self {
32        Self::new()
33    }
34}
35
36#[async_trait]
37impl HttpClient for ReqwestClient {
38    async fn send(&self, request: HttpRequest) -> Result<HttpResponse, HttpError> {
39        let method = match request.method {
40            Method::Get => reqwest::Method::GET,
41            Method::Post => reqwest::Method::POST,
42        };
43        let mut builder = self.client.request(method, &request.url);
44        for (name, value) in request.headers {
45            builder = builder.header(name, value);
46        }
47        if let Some(body) = request.body {
48            builder = builder.body(body);
49        }
50        let response = builder.send().await.map_err(HttpError::transport)?;
51        let status = response.status().as_u16();
52        let headers = response
53            .headers()
54            .iter()
55            .filter_map(|(name, value)| Some((name.to_string(), value.to_str().ok()?.to_string())))
56            .collect();
57        let body = response.bytes().await.map_err(HttpError::transport)?;
58        Ok(HttpResponse {
59            status,
60            headers,
61            body: body.to_vec(),
62        })
63    }
64}