Skip to main content

shared_framework/utils/
http_client.rs

1//! Outbound JSON HTTP client.
2//!
3//! [`HttpClient`] wraps `reqwest` with Rustls TLS for JSON GET/POST calls.
4//! Responses with non-success status codes surface as errors.
5//!
6//! ```ignore
7//! let client = HttpClient::new();
8//! let dto: MyDto = client.get("https://example.com/api").await?;
9//! ```
10
11use serde::{de::DeserializeOwned, Serialize};
12
13/// Thin `reqwest`-backed client that sends and receives JSON.
14#[derive(Clone)]
15pub struct HttpClient {
16    inner: reqwest::Client,
17}
18
19impl HttpClient {
20    /// Creates a client with Rustls TLS, falling back to a default client on builder failure.
21    pub fn new() -> Self {
22        Self { inner: reqwest::Client::builder().use_rustls_tls().build().unwrap_or_else(|_| reqwest::Client::new()) }
23    }
24
25    /// Sends a GET request and decodes the JSON response as `T`.
26    /// Returns an error on transport failure, non-success status, or invalid JSON.
27    pub async fn get<T: DeserializeOwned>(&self, url: &str) -> anyhow::Result<T> {
28        let resp = self.inner.get(url).send().await?.error_for_status()?;
29        Ok(resp.json::<T>().await?)
30    }
31
32    /// Sends a POST request with a JSON body and decodes the JSON response as `T`.
33    /// Returns an error on transport failure, non-success status, or invalid JSON.
34    pub async fn post<T: DeserializeOwned, B: Serialize>(&self, url: &str, body: &B) -> anyhow::Result<T> {
35        let resp = self.inner.post(url).json(body).send().await?.error_for_status()?;
36        Ok(resp.json::<T>().await?)
37    }
38
39    /// Sends a POST request with a JSON body and ignores the response body.
40    /// Returns an error on transport failure or non-success status.
41    pub async fn post_empty<B: Serialize>(&self, url: &str, body: &B) -> anyhow::Result<()> {
42        self.inner.post(url).json(body).send().await?.error_for_status()?;
43        Ok(())
44    }
45}
46
47impl Default for HttpClient {
48    fn default() -> Self { Self::new() }
49}