shared-framework 0.0.17

Reusable building blocks for HTTP services — Hyper routing, SeaORM data layer, validation, OpenAPI docs, jobs, queues, cache.
Documentation
//! Outbound JSON HTTP client.
//!
//! [`HttpClient`] wraps `reqwest` with Rustls TLS for JSON GET/POST calls.
//! Responses with non-success status codes surface as errors.
//!
//! ```ignore
//! let client = HttpClient::new();
//! let dto: MyDto = client.get("https://example.com/api").await?;
//! ```

use serde::{de::DeserializeOwned, Serialize};

/// Thin `reqwest`-backed client that sends and receives JSON.
#[derive(Clone)]
pub struct HttpClient {
    inner: reqwest::Client,
}

impl HttpClient {
    /// Creates a client with Rustls TLS, falling back to a default client on builder failure.
    pub fn new() -> Self {
        Self { inner: reqwest::Client::builder().use_rustls_tls().build().unwrap_or_else(|_| reqwest::Client::new()) }
    }

    /// Sends a GET request and decodes the JSON response as `T`.
    /// Returns an error on transport failure, non-success status, or invalid JSON.
    pub async fn get<T: DeserializeOwned>(&self, url: &str) -> anyhow::Result<T> {
        let resp = self.inner.get(url).send().await?.error_for_status()?;
        Ok(resp.json::<T>().await?)
    }

    /// Sends a POST request with a JSON body and decodes the JSON response as `T`.
    /// Returns an error on transport failure, non-success status, or invalid JSON.
    pub async fn post<T: DeserializeOwned, B: Serialize>(&self, url: &str, body: &B) -> anyhow::Result<T> {
        let resp = self.inner.post(url).json(body).send().await?.error_for_status()?;
        Ok(resp.json::<T>().await?)
    }

    /// Sends a POST request with a JSON body and ignores the response body.
    /// Returns an error on transport failure or non-success status.
    pub async fn post_empty<B: Serialize>(&self, url: &str, body: &B) -> anyhow::Result<()> {
        self.inner.post(url).json(body).send().await?.error_for_status()?;
        Ok(())
    }
}

impl Default for HttpClient {
    fn default() -> Self { Self::new() }
}