openai_rust_sdk/api/base/
config.rs1use crate::error::{OpenAIError, Result};
4
5pub const DEFAULT_BASE_URL: &str = "https://api.openai.com";
7
8#[derive(Debug, Clone)]
10pub struct ClientConfig {
11 pub api_key: String,
13 pub base_url: String,
15}
16
17impl ClientConfig {
18 pub fn new<S: Into<String>>(api_key: S) -> Result<Self> {
20 let api_key = Self::validate_api_key(api_key)?;
21 Ok(Self {
22 api_key,
23 base_url: DEFAULT_BASE_URL.to_string(),
24 })
25 }
26
27 pub fn new_with_base_url<S: Into<String>>(api_key: S, base_url: S) -> Result<Self> {
29 let api_key = Self::validate_api_key(api_key)?;
30 Ok(Self {
31 api_key,
32 base_url: base_url.into(),
33 })
34 }
35
36 fn validate_api_key<S: Into<String>>(api_key: S) -> Result<String> {
38 let api_key = api_key.into();
39 if api_key.trim().is_empty() {
40 return Err(OpenAIError::authentication("API key cannot be empty"));
41 }
42 Ok(api_key)
43 }
44
45 pub fn with_base_url<S: Into<String>>(mut self, base_url: S) -> Self {
47 self.base_url = base_url.into();
48 self
49 }
50
51 #[must_use]
53 pub fn api_key(&self) -> &str {
54 &self.api_key
55 }
56
57 #[must_use]
59 pub fn base_url(&self) -> &str {
60 &self.base_url
61 }
62}
63
64pub trait Validate {
66 fn validate(&self) -> std::result::Result<(), String>;
68}
69
70pub fn validate_request<T>(request: &T) -> Result<()>
89where
90 T: Validate,
91{
92 request.validate().map_err(OpenAIError::InvalidRequest)
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_client_config_new() {
101 let config = ClientConfig::new("test-key").unwrap();
102 assert_eq!(config.api_key(), "test-key");
103 assert_eq!(config.base_url(), DEFAULT_BASE_URL);
104 }
105
106 #[test]
107 fn test_client_config_with_base_url() {
108 let config = ClientConfig::new_with_base_url("test-key", "https://custom.api.com").unwrap();
109 assert_eq!(config.api_key(), "test-key");
110 assert_eq!(config.base_url(), "https://custom.api.com");
111 }
112
113 #[test]
114 fn test_client_config_empty_api_key() {
115 let result = ClientConfig::new("");
116 assert!(result.is_err());
117 }
118
119 #[test]
120 fn test_validate_request_success() {
121 struct TestRequest {
122 valid: bool,
123 }
124
125 impl Validate for TestRequest {
126 fn validate(&self) -> std::result::Result<(), String> {
127 if self.valid {
128 Ok(())
129 } else {
130 Err("Invalid request".to_string())
131 }
132 }
133 }
134
135 let valid_request = TestRequest { valid: true };
136 let result = validate_request(&valid_request);
137 assert!(result.is_ok());
138 }
139
140 #[test]
141 fn test_validate_request_failure() {
142 struct TestRequest {
143 valid: bool,
144 }
145
146 impl Validate for TestRequest {
147 fn validate(&self) -> std::result::Result<(), String> {
148 if self.valid {
149 Ok(())
150 } else {
151 Err("Invalid request".to_string())
152 }
153 }
154 }
155
156 let invalid_request = TestRequest { valid: false };
157 let result = validate_request(&invalid_request);
158 assert!(result.is_err());
159
160 if let Err(e) = result {
161 if let OpenAIError::InvalidRequest(msg) = e {
162 assert_eq!(msg, "Invalid request");
163 } else {
164 panic!("Expected InvalidRequest error, got: {:?}", e);
165 }
166 }
167 }
168}