anthropic_async/
client.rs1use backon::{ExponentialBuilder, Retryable};
2use serde::{Serialize, de::DeserializeOwned};
3
4use crate::{config::Config, error::AnthropicError, retry};
5
6#[derive(Debug, Clone)]
11pub struct Client<C: Config> {
12 http: reqwest::Client,
13 config: C,
14 backoff: ExponentialBuilder,
15}
16
17impl Client<crate::config::AnthropicConfig> {
18 #[must_use]
24 pub fn new() -> Self {
25 Self::with_config(crate::config::AnthropicConfig::new())
26 }
27}
28
29impl<C: Config + Default> Default for Client<C> {
30 fn default() -> Self {
31 Self::with_config(C::default())
32 }
33}
34
35impl<C: Config> Client<C> {
36 #[must_use]
42 pub fn with_config(config: C) -> Self {
43 Self {
44 http: reqwest::Client::builder()
45 .connect_timeout(std::time::Duration::from_secs(5))
46 .timeout(std::time::Duration::from_secs(600))
47 .build()
48 .expect("reqwest client"),
49 config,
50 backoff: retry::default_backoff_builder(),
51 }
52 }
53
54 #[must_use]
58 pub fn with_http_client(mut self, http: reqwest::Client) -> Self {
59 self.http = http;
60 self
61 }
62
63 #[must_use]
67 pub const fn with_backoff(mut self, backoff: ExponentialBuilder) -> Self {
68 self.backoff = backoff;
69 self
70 }
71
72 #[must_use]
74 pub const fn config(&self) -> &C {
75 &self.config
76 }
77
78 pub(crate) async fn get<O: DeserializeOwned>(&self, path: &str) -> Result<O, AnthropicError> {
79 let mk = || async {
80 let headers = self.config.headers()?;
81 Ok(self
82 .http
83 .get(self.config.url(path))
84 .headers(headers)
85 .query(&self.config.query())
86 .build()?)
87 };
88 self.execute(mk).await
89 }
90
91 pub(crate) async fn get_with_query<Q, O>(
92 &self,
93 path: &str,
94 query: &Q,
95 ) -> Result<O, AnthropicError>
96 where
97 Q: Serialize + Sync + ?Sized,
98 O: DeserializeOwned,
99 {
100 let mk = || async {
101 let headers = self.config.headers()?;
102 Ok(self
103 .http
104 .get(self.config.url(path))
105 .headers(headers)
106 .query(&self.config.query())
107 .query(query)
108 .build()?)
109 };
110 self.execute(mk).await
111 }
112
113 pub(crate) async fn post<I, O>(&self, path: &str, body: I) -> Result<O, AnthropicError>
114 where
115 I: Serialize + Send + Sync,
116 O: DeserializeOwned,
117 {
118 let mk = || async {
119 let headers = self.config.headers()?;
120 Ok(self
121 .http
122 .post(self.config.url(path))
123 .headers(headers)
124 .query(&self.config.query())
125 .json(&body)
126 .build()?)
127 };
128 self.execute(mk).await
129 }
130
131 #[cfg(feature = "streaming")]
135 pub(crate) async fn post_stream<I: Serialize + Send + Sync>(
136 &self,
137 path: &str,
138 body: I,
139 ) -> Result<reqwest::Response, AnthropicError> {
140 self.config.validate_auth()?;
142
143 let headers = self.config.headers()?;
144 let request = self
145 .http
146 .post(self.config.url(path))
147 .headers(headers)
148 .query(&self.config.query())
149 .json(&body)
150 .build()?;
151
152 let response = self
153 .http
154 .execute(request)
155 .await
156 .map_err(AnthropicError::Reqwest)?;
157
158 let status = response.status();
159 if status.is_success() {
160 Ok(response)
161 } else {
162 let bytes = response.bytes().await.map_err(AnthropicError::Reqwest)?;
163 Err(crate::error::deserialize_api_error(status, &bytes))
164 }
165 }
166
167 async fn execute<O, M, Fut>(&self, mk: M) -> Result<O, AnthropicError>
168 where
169 O: DeserializeOwned,
170 M: Fn() -> Fut + Send + Sync,
171 Fut: core::future::Future<Output = Result<reqwest::Request, AnthropicError>> + Send,
172 {
173 self.config.validate_auth()?;
175
176 let bytes = self.execute_raw(mk).await?;
177 let resp: O =
178 serde_json::from_slice(&bytes).map_err(|e| crate::error::map_deser(&e, &bytes))?;
179 Ok(resp)
180 }
181
182 async fn execute_raw<M, Fut>(&self, mk: M) -> Result<bytes::Bytes, AnthropicError>
183 where
184 M: Fn() -> Fut + Send + Sync,
185 Fut: core::future::Future<Output = Result<reqwest::Request, AnthropicError>> + Send,
186 {
187 let http_client = self.http.clone();
188
189 (|| async {
190 let request = mk().await?;
191 let response = http_client
192 .execute(request)
193 .await
194 .map_err(AnthropicError::Reqwest)?;
195
196 let status = response.status();
197 let bytes = response.bytes().await.map_err(AnthropicError::Reqwest)?;
198
199 if status.is_success() {
200 return Ok(bytes);
201 }
202
203 Err(crate::error::deserialize_api_error(status, &bytes))
204 })
205 .retry(self.backoff)
206 .when(AnthropicError::is_retryable)
207 .await
208 }
209}