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