outfox_openai/
request_options.rs1use reqwest::header::HeaderMap;
2use serde::Serialize;
3use url::Url;
4
5use crate::config::OPENAI_API_BASE;
6use crate::error::OpenAIError;
7
8#[derive(Clone, Debug, Default)]
9pub struct RequestOptions {
10 query: Option<Vec<(String, String)>>,
11 headers: Option<HeaderMap>,
12 path: Option<String>,
13}
14
15impl RequestOptions {
16 pub(crate) fn new() -> Self {
17 Self {
18 query: None,
19 headers: None,
20 path: None,
21 }
22 }
23
24 pub(crate) fn with_path(&mut self, path: &str) -> Result<(), OpenAIError> {
25 if path.is_empty() {
26 return Err(OpenAIError::InvalidArgument(
27 "Path cannot be empty".to_string(),
28 ));
29 }
30 self.path = Some(path.to_string());
31 Ok(())
32 }
33
34 pub(crate) fn with_headers(&mut self, headers: HeaderMap) {
35 if let Some(existing_headers) = &mut self.headers {
37 existing_headers.extend(headers);
38 } else {
39 self.headers = Some(headers);
40 }
41 }
42
43 pub(crate) fn with_header<K, V>(&mut self, key: K, value: V) -> Result<(), OpenAIError>
44 where
45 K: reqwest::header::IntoHeaderName,
46 V: TryInto<reqwest::header::HeaderValue>,
47 V::Error: Into<reqwest::header::InvalidHeaderValue>,
48 {
49 let value = value.try_into().map_err(|e| {
50 OpenAIError::InvalidArgument(format!("Invalid header value: {}", e.into()))
51 })?;
52 if let Some(headers) = &mut self.headers {
53 headers.insert(key, value);
54 } else {
55 let mut headers = HeaderMap::new();
56 headers.insert(key, value);
57 self.headers = Some(headers);
58 }
59 Ok(())
60 }
61
62 pub(crate) fn with_query<Q: Serialize + ?Sized>(
63 &mut self,
64 query: &Q,
65 ) -> Result<(), OpenAIError> {
66 let mut url = Url::parse(OPENAI_API_BASE)
70 .map_err(|e| OpenAIError::InvalidArgument(format!("Failed to create URL: {}", e)))?;
71
72 {
73 let mut pairs = url.query_pairs_mut();
74 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
75
76 query
77 .serialize(serializer)
78 .map_err(|e| OpenAIError::InvalidArgument(format!("Invalid query: {}", e)))?;
79 }
80
81 let query = self.query.get_or_insert_with(Vec::new);
83 for (key, value) in url.query_pairs() {
84 query.push((key.to_string(), value.to_string()));
85 }
86
87 Ok(())
88 }
89
90 pub(crate) fn query(&self) -> &[(String, String)] {
91 self.query.as_deref().unwrap_or(&[])
92 }
93
94 pub(crate) fn headers(&self) -> Option<&HeaderMap> {
95 self.headers.as_ref()
96 }
97
98 pub(crate) fn path(&self) -> Option<&String> {
99 self.path.as_ref()
100 }
101}