hooksmith_core/client.rs
1use reqwest::Client;
2use serde::Serialize;
3
4/// A thin wrapper around [`reqwest::Client`] shared by all hooksmith service crates.
5///
6/// Service crates (e.g. `discord_hook`, `slack_hook`) hold one of these,
7/// configure it at construction time, and call [`HttpClient::post_json`] to
8/// fire requests.
9///
10/// **TLS configuration** is the responsibility of the service crate — build a
11/// [`reqwest::Client`] with your chosen TLS backend and pass it in via
12/// [`HttpClient::with_reqwest`].
13pub struct HttpClient {
14 inner: Client,
15}
16
17impl HttpClient {
18 /// Create a client backed by a freshly-constructed [`reqwest::Client`].
19 ///
20 /// A 30-second request timeout is applied by default so that a slow or
21 /// unresponsive endpoint can never hang your application indefinitely.
22 /// Override this by building your own [`reqwest::Client`] and passing it
23 /// to [`HttpClient::with_reqwest`].
24 pub fn new() -> Self {
25 let inner = Client::builder()
26 .timeout(std::time::Duration::from_secs(30))
27 .build()
28 .expect("failed to initialise reqwest client — TLS backend unavailable");
29 Self { inner }
30 }
31
32 /// Wrap an existing [`reqwest::Client`].
33 ///
34 /// Use this to share a connection pool or inject custom configuration
35 /// (timeouts, proxies, etc.) across your application.
36 pub fn with_reqwest(client: Client) -> Self {
37 Self { inner: client }
38 }
39
40 /// POST `body` serialized as JSON to `url` and return the raw response.
41 pub async fn post_json(
42 &self,
43 url: &str,
44 body: &impl Serialize,
45 ) -> Result<reqwest::Response, reqwest::Error> {
46 self.inner.post(url).json(body).send().await
47 }
48
49 /// Access the underlying [`reqwest::Client`] for advanced use-cases.
50 pub fn inner(&self) -> &Client {
51 &self.inner
52 }
53}
54
55impl Default for HttpClient {
56 fn default() -> Self {
57 Self::new()
58 }
59}