Skip to main content

voltaria_sdk/
client.rs

1use crate::api::resources::ApiClient;
2use crate::Environment;
3use crate::{ApiError, ClientConfig};
4use std::collections::HashMap;
5use std::time::Duration;
6/// Builder for creating API clients with custom configuration
7pub struct ApiClientBuilder {
8    config: ClientConfig,
9}
10impl Default for ApiClientBuilder {
11    fn default() -> Self {
12        Self {
13            config: ClientConfig::default(),
14        }
15    }
16}
17impl ApiClientBuilder {
18    /// Create a new builder with the specified base URL
19    pub fn new(base_url: impl Into<String>) -> Self {
20        let mut config = ClientConfig::default();
21        config.base_url = base_url.into();
22        Self { config }
23    }
24
25    /// Set the environment, updating the base URL
26    pub fn environment(mut self, environment: Environment) -> Self {
27        self.config.base_url = environment.url().to_string();
28        self
29    }
30
31    /// Set the API key for authentication
32    pub fn api_key(mut self, key: impl Into<String>) -> Self {
33        self.config.api_key = Some(key.into());
34        self
35    }
36
37    /// Set the bearer token for authentication
38    pub fn token(mut self, token: impl Into<String>) -> Self {
39        self.config.token = Some(token.into());
40        self
41    }
42
43    /// Set the username for basic authentication
44    pub fn username(mut self, username: impl Into<String>) -> Self {
45        self.config.username = Some(username.into());
46        self
47    }
48
49    /// Set the password for basic authentication
50    pub fn password(mut self, password: impl Into<String>) -> Self {
51        self.config.password = Some(password.into());
52        self
53    }
54
55    /// Set the OAuth client ID for client credentials authentication
56    pub fn client_id(mut self, client_id: impl Into<String>) -> Self {
57        self.config.client_id = Some(client_id.into());
58        self
59    }
60
61    /// Set the OAuth client secret for client credentials authentication
62    pub fn client_secret(mut self, client_secret: impl Into<String>) -> Self {
63        self.config.client_secret = Some(client_secret.into());
64        self
65    }
66
67    /// Set OAuth credentials (client_id and client_secret) for client credentials authentication
68    pub fn oauth_credentials(
69        mut self,
70        client_id: impl Into<String>,
71        client_secret: impl Into<String>,
72    ) -> Self {
73        self.config.client_id = Some(client_id.into());
74        self.config.client_secret = Some(client_secret.into());
75        self
76    }
77
78    /// Set the request timeout
79    pub fn timeout(mut self, timeout: Duration) -> Self {
80        self.config.timeout = timeout;
81        self
82    }
83
84    /// Set the maximum number of retries
85    pub fn max_retries(mut self, retries: u32) -> Self {
86        self.config.max_retries = retries;
87        self
88    }
89
90    /// Add a custom header
91    pub fn custom_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
92        self.config.custom_headers.insert(key.into(), value.into());
93        self
94    }
95
96    /// Add multiple custom headers
97    pub fn custom_headers(mut self, headers: HashMap<String, String>) -> Self {
98        self.config.custom_headers.extend(headers);
99        self
100    }
101
102    /// Set the user agent
103    pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
104        self.config.user_agent = user_agent.into();
105        self
106    }
107
108    /// Build the client with validation
109    pub fn build(self) -> Result<ApiClient, ApiError> {
110        ApiClient::new(self.config)
111    }
112}
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_environment() {
119        let builder = ApiClientBuilder::default().environment(Environment::default());
120        assert_eq!(
121            builder.config.base_url,
122            Environment::default().url().to_string()
123        );
124    }
125
126    #[test]
127    fn test_new_sets_base_url() {
128        let builder = ApiClientBuilder::new("https://api.example.com");
129        assert_eq!(builder.config.base_url, "https://api.example.com");
130    }
131
132    #[test]
133    fn test_api_key() {
134        let builder = ApiClientBuilder::new("https://api.example.com").api_key("my-key");
135        assert_eq!(builder.config.api_key, Some("my-key".to_string()));
136    }
137
138    #[test]
139    fn test_token() {
140        let builder = ApiClientBuilder::new("https://api.example.com").token("my-token");
141        assert_eq!(builder.config.token, Some("my-token".to_string()));
142    }
143
144    #[test]
145    fn test_username() {
146        let builder = ApiClientBuilder::new("https://api.example.com").username("user");
147        assert_eq!(builder.config.username, Some("user".to_string()));
148    }
149
150    #[test]
151    fn test_password() {
152        let builder = ApiClientBuilder::new("https://api.example.com").password("pass");
153        assert_eq!(builder.config.password, Some("pass".to_string()));
154    }
155
156    #[test]
157    fn test_client_id() {
158        let builder = ApiClientBuilder::new("https://api.example.com").client_id("cid");
159        assert_eq!(builder.config.client_id, Some("cid".to_string()));
160    }
161
162    #[test]
163    fn test_client_secret() {
164        let builder = ApiClientBuilder::new("https://api.example.com").client_secret("secret");
165        assert_eq!(builder.config.client_secret, Some("secret".to_string()));
166    }
167
168    #[test]
169    fn test_oauth_credentials() {
170        let builder =
171            ApiClientBuilder::new("https://api.example.com").oauth_credentials("cid", "secret");
172        assert_eq!(builder.config.client_id, Some("cid".to_string()));
173        assert_eq!(builder.config.client_secret, Some("secret".to_string()));
174    }
175
176    #[test]
177    fn test_timeout() {
178        let builder =
179            ApiClientBuilder::new("https://api.example.com").timeout(Duration::from_secs(120));
180        assert_eq!(builder.config.timeout, Duration::from_secs(120));
181    }
182
183    #[test]
184    fn test_max_retries() {
185        let builder = ApiClientBuilder::new("https://api.example.com").max_retries(5);
186        assert_eq!(builder.config.max_retries, 5);
187    }
188
189    #[test]
190    fn test_custom_header() {
191        let builder =
192            ApiClientBuilder::new("https://api.example.com").custom_header("X-Custom", "value");
193        assert_eq!(
194            builder.config.custom_headers.get("X-Custom"),
195            Some(&"value".to_string())
196        );
197    }
198
199    #[test]
200    fn test_custom_headers_multiple() {
201        let mut headers = HashMap::new();
202        headers.insert("X-One".to_string(), "1".to_string());
203        headers.insert("X-Two".to_string(), "2".to_string());
204        let builder = ApiClientBuilder::new("https://api.example.com").custom_headers(headers);
205        assert_eq!(
206            builder.config.custom_headers.get("X-One"),
207            Some(&"1".to_string())
208        );
209        assert_eq!(
210            builder.config.custom_headers.get("X-Two"),
211            Some(&"2".to_string())
212        );
213    }
214
215    #[test]
216    fn test_user_agent() {
217        let builder = ApiClientBuilder::new("https://api.example.com").user_agent("my-sdk/1.0");
218        assert_eq!(builder.config.user_agent, "my-sdk/1.0");
219    }
220
221    #[test]
222    fn test_full_builder_chain() {
223        let builder = ApiClientBuilder::new("https://api.example.com")
224            .api_key("key")
225            .token("tok")
226            .username("user")
227            .password("pass")
228            .timeout(Duration::from_secs(60))
229            .max_retries(3)
230            .custom_header("X-Foo", "bar")
231            .user_agent("test/1.0");
232        assert_eq!(builder.config.base_url, "https://api.example.com");
233        assert_eq!(builder.config.api_key, Some("key".to_string()));
234        assert_eq!(builder.config.token, Some("tok".to_string()));
235        assert_eq!(builder.config.username, Some("user".to_string()));
236        assert_eq!(builder.config.password, Some("pass".to_string()));
237        assert_eq!(builder.config.timeout, Duration::from_secs(60));
238        assert_eq!(builder.config.max_retries, 3);
239        assert_eq!(builder.config.user_agent, "test/1.0");
240    }
241
242    #[test]
243    fn test_build_succeeds() {
244        let result = ApiClientBuilder::new("https://api.example.com").build();
245        assert!(result.is_ok());
246    }
247}