Skip to main content

tracedb_sdk/core/
request_options.rs

1use std::collections::HashMap;
2/// Options for customizing individual requests
3#[derive(Debug, Clone, Default)]
4pub struct RequestOptions {
5    /// API key for authentication (overrides client-level API key)
6    pub api_key: Option<String>,
7    /// Bearer token for authentication (overrides client-level token)
8    pub token: Option<String>,
9    /// Maximum number of retry attempts for failed requests
10    pub max_retries: Option<u32>,
11    /// Request timeout in seconds (overrides client-level timeout)
12    pub timeout_seconds: Option<u64>,
13    /// Additional headers to include in the request
14    pub additional_headers: HashMap<String, String>,
15    /// Additional query parameters to include in the request
16    pub additional_query_params: HashMap<String, String>,
17}
18
19impl RequestOptions {
20    pub fn new() -> Self {
21        Self::default()
22    }
23
24    pub fn api_key(mut self, key: impl Into<String>) -> Self {
25        self.api_key = Some(key.into());
26        self
27    }
28
29    pub fn token(mut self, token: impl Into<String>) -> Self {
30        self.token = Some(token.into());
31        self
32    }
33
34    pub fn max_retries(mut self, retries: u32) -> Self {
35        self.max_retries = Some(retries);
36        self
37    }
38
39    pub fn timeout_seconds(mut self, timeout: u64) -> Self {
40        self.timeout_seconds = Some(timeout);
41        self
42    }
43
44    pub fn additional_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
45        self.additional_headers.insert(key.into(), value.into());
46        self
47    }
48
49    pub fn additional_query_param(
50        mut self,
51        key: impl Into<String>,
52        value: impl Into<String>,
53    ) -> Self {
54        self.additional_query_params
55            .insert(key.into(), value.into());
56        self
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_default_has_no_values() {
66        let opts = RequestOptions::default();
67        assert!(opts.api_key.is_none());
68        assert!(opts.token.is_none());
69        assert!(opts.max_retries.is_none());
70        assert!(opts.timeout_seconds.is_none());
71        assert!(opts.additional_headers.is_empty());
72        assert!(opts.additional_query_params.is_empty());
73    }
74
75    #[test]
76    fn test_new_equals_default() {
77        let opts = RequestOptions::new();
78        assert!(opts.api_key.is_none());
79        assert!(opts.token.is_none());
80        assert!(opts.max_retries.is_none());
81        assert!(opts.timeout_seconds.is_none());
82        assert!(opts.additional_headers.is_empty());
83        assert!(opts.additional_query_params.is_empty());
84    }
85
86    #[test]
87    fn test_api_key() {
88        let opts = RequestOptions::new().api_key("my-key");
89        assert_eq!(opts.api_key, Some("my-key".to_string()));
90    }
91
92    #[test]
93    fn test_token() {
94        let opts = RequestOptions::new().token("my-token");
95        assert_eq!(opts.token, Some("my-token".to_string()));
96    }
97
98    #[test]
99    fn test_max_retries() {
100        let opts = RequestOptions::new().max_retries(3);
101        assert_eq!(opts.max_retries, Some(3));
102    }
103
104    #[test]
105    fn test_timeout_seconds() {
106        let opts = RequestOptions::new().timeout_seconds(30);
107        assert_eq!(opts.timeout_seconds, Some(30));
108    }
109
110    #[test]
111    fn test_additional_header() {
112        let opts = RequestOptions::new().additional_header("X-Custom", "value");
113        assert_eq!(
114            opts.additional_headers.get("X-Custom"),
115            Some(&"value".to_string())
116        );
117    }
118
119    #[test]
120    fn test_additional_headers_accumulate() {
121        let opts = RequestOptions::new()
122            .additional_header("X-First", "1")
123            .additional_header("X-Second", "2");
124        assert_eq!(opts.additional_headers.len(), 2);
125        assert_eq!(
126            opts.additional_headers.get("X-First"),
127            Some(&"1".to_string())
128        );
129        assert_eq!(
130            opts.additional_headers.get("X-Second"),
131            Some(&"2".to_string())
132        );
133    }
134
135    #[test]
136    fn test_additional_query_param() {
137        let opts = RequestOptions::new().additional_query_param("page", "1");
138        assert_eq!(
139            opts.additional_query_params.get("page"),
140            Some(&"1".to_string())
141        );
142    }
143
144    #[test]
145    fn test_additional_query_params_accumulate() {
146        let opts = RequestOptions::new()
147            .additional_query_param("page", "1")
148            .additional_query_param("limit", "10");
149        assert_eq!(opts.additional_query_params.len(), 2);
150        assert_eq!(
151            opts.additional_query_params.get("page"),
152            Some(&"1".to_string())
153        );
154        assert_eq!(
155            opts.additional_query_params.get("limit"),
156            Some(&"10".to_string())
157        );
158    }
159
160    #[test]
161    fn test_full_method_chaining() {
162        let opts = RequestOptions::new()
163            .api_key("key")
164            .token("tok")
165            .max_retries(5)
166            .timeout_seconds(60)
167            .additional_header("X-Foo", "bar")
168            .additional_query_param("q", "search");
169        assert_eq!(opts.api_key, Some("key".to_string()));
170        assert_eq!(opts.token, Some("tok".to_string()));
171        assert_eq!(opts.max_retries, Some(5));
172        assert_eq!(opts.timeout_seconds, Some(60));
173        assert_eq!(opts.additional_headers.len(), 1);
174        assert_eq!(opts.additional_query_params.len(), 1);
175    }
176}