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}