Skip to main content

polyoxide_core/
client.rs

1use std::time::Duration;
2
3use url::Url;
4
5use crate::error::ApiError;
6
7/// Default request timeout in milliseconds
8pub const DEFAULT_TIMEOUT_MS: u64 = 30_000;
9/// Default connection pool size per host
10pub const DEFAULT_POOL_SIZE: usize = 10;
11
12/// Shared HTTP client with base URL.
13///
14/// This is the common structure used by all API clients to hold
15/// the configured reqwest client and base URL.
16#[derive(Debug, Clone)]
17pub struct HttpClient {
18    /// The underlying reqwest HTTP client
19    pub client: reqwest::Client,
20    /// Base URL for API requests
21    pub base_url: Url,
22}
23
24/// Builder for configuring HTTP clients.
25///
26/// Provides a consistent way to configure HTTP clients across all API crates
27/// with sensible defaults.
28///
29/// # Example
30///
31/// ```
32/// use polyoxide_core::HttpClientBuilder;
33///
34/// let client = HttpClientBuilder::new("https://api.example.com")
35///     .timeout_ms(60_000)
36///     .pool_size(20)
37///     .build()
38///     .unwrap();
39/// ```
40pub struct HttpClientBuilder {
41    base_url: String,
42    timeout_ms: u64,
43    pool_size: usize,
44}
45
46impl HttpClientBuilder {
47    /// Create a new HTTP client builder with the given base URL.
48    pub fn new(base_url: impl Into<String>) -> Self {
49        Self {
50            base_url: base_url.into(),
51            timeout_ms: DEFAULT_TIMEOUT_MS,
52            pool_size: DEFAULT_POOL_SIZE,
53        }
54    }
55
56    /// Set request timeout in milliseconds.
57    ///
58    /// Default: 30,000ms (30 seconds)
59    pub fn timeout_ms(mut self, timeout: u64) -> Self {
60        self.timeout_ms = timeout;
61        self
62    }
63
64    /// Set connection pool size per host.
65    ///
66    /// Default: 10 connections
67    pub fn pool_size(mut self, size: usize) -> Self {
68        self.pool_size = size;
69        self
70    }
71
72    /// Build the HTTP client.
73    pub fn build(self) -> Result<HttpClient, ApiError> {
74        let client = reqwest::Client::builder()
75            .timeout(Duration::from_millis(self.timeout_ms))
76            .pool_max_idle_per_host(self.pool_size)
77            .build()?;
78
79        let base_url = Url::parse(&self.base_url)?;
80
81        Ok(HttpClient { client, base_url })
82    }
83}
84
85impl Default for HttpClientBuilder {
86    fn default() -> Self {
87        Self {
88            base_url: String::new(),
89            timeout_ms: DEFAULT_TIMEOUT_MS,
90            pool_size: DEFAULT_POOL_SIZE,
91        }
92    }
93}