openrouter_rust/
client.rs1use crate::error::Result;
2use reqwest::{header, Client};
3use std::time::Duration;
4
5const DEFAULT_BASE_URL: &str = "https://openrouter.ai/api/v1";
6const DEFAULT_TIMEOUT: Duration = Duration::from_secs(60);
7
8#[derive(Clone, Debug)]
9pub struct OpenRouterClient {
10 pub(crate) client: Client,
11 pub api_key: String,
12 pub base_url: String,
13 pub http_referer: Option<String>,
14 pub x_title: Option<String>,
15}
16
17impl OpenRouterClient {
18 pub fn builder() -> OpenRouterClientBuilder {
19 OpenRouterClientBuilder::new()
20 }
21
22 pub fn build_headers(&self) -> Result<header::HeaderMap> {
23 let mut headers = header::HeaderMap::new();
24
25 let auth_value = format!("Bearer {}", self.api_key).parse().map_err(|e| {
26 crate::error::OpenRouterError::ConfigError(format!("Invalid API key: {}", e))
27 })?;
28 headers.insert(header::AUTHORIZATION, auth_value);
29
30 headers.insert(header::CONTENT_TYPE, "application/json".parse().unwrap());
31
32 if let Some(ref referer) = self.http_referer {
33 if let Ok(value) = referer.parse() {
34 headers.insert("HTTP-Referer", value);
35 }
36 }
37
38 if let Some(ref title) = self.x_title {
39 if let Ok(value) = title.parse() {
40 headers.insert("X-Title", value);
41 }
42 }
43
44 Ok(headers)
45 }
46}
47
48pub struct OpenRouterClientBuilder {
49 api_key: Option<String>,
50 base_url: Option<String>,
51 http_referer: Option<String>,
52 x_title: Option<String>,
53 timeout: Option<Duration>,
54}
55
56impl OpenRouterClientBuilder {
57 pub fn new() -> Self {
58 Self {
59 api_key: None,
60 base_url: None,
61 http_referer: None,
62 x_title: None,
63 timeout: None,
64 }
65 }
66
67 pub fn api_key(mut self, key: impl Into<String>) -> Self {
68 self.api_key = Some(key.into());
69 self
70 }
71
72 pub fn base_url(mut self, url: impl Into<String>) -> Self {
73 self.base_url = Some(url.into());
74 self
75 }
76
77 pub fn http_referer(mut self, referer: impl Into<String>) -> Self {
78 self.http_referer = Some(referer.into());
79 self
80 }
81
82 pub fn x_title(mut self, title: impl Into<String>) -> Self {
83 self.x_title = Some(title.into());
84 self
85 }
86
87 pub fn timeout(mut self, timeout: Duration) -> Self {
88 self.timeout = Some(timeout);
89 self
90 }
91
92 pub fn build(self) -> Result<OpenRouterClient> {
93 let api_key = self.api_key.ok_or_else(|| {
94 crate::error::OpenRouterError::ConfigError("API key is required".to_string())
95 })?;
96
97 let client = Client::builder()
98 .timeout(self.timeout.unwrap_or(DEFAULT_TIMEOUT))
99 .build()
100 .map_err(crate::error::OpenRouterError::HttpError)?;
101
102 Ok(OpenRouterClient {
103 client,
104 api_key,
105 base_url: self
106 .base_url
107 .unwrap_or_else(|| DEFAULT_BASE_URL.to_string()),
108 http_referer: self.http_referer,
109 x_title: self.x_title,
110 })
111 }
112}
113
114impl Default for OpenRouterClientBuilder {
115 fn default() -> Self {
116 Self::new()
117 }
118}