1use std::collections::HashMap;
7use std::time::Duration;
8
9use bytes::Bytes;
10use http::{HeaderMap, Method};
11use indexmap::IndexMap;
12
13use crate::auth::Auth;
14use crate::backend::HttpBody;
15use crate::cancel::CancellationToken;
16use crate::client::Client;
17use crate::error::Error;
18use crate::response::Response;
19use crate::retry::RetryPolicy;
20use crate::url_build::QueryValue;
21use crate::Result;
22
23#[cfg(feature = "json")]
24use crate::json_parser::JsonParserFn;
25
26pub struct RequestBuilder<'a> {
32 pub(crate) client: &'a Client,
33 pub(crate) method: Method,
34 pub(crate) path: String,
35 pub(crate) params: HashMap<String, String>,
36 pub(crate) query: IndexMap<String, QueryValue>,
37 pub(crate) headers: HeaderMap,
38 pub(crate) body: HttpBody,
39 #[cfg(feature = "multipart")]
40 pub(crate) multipart: Option<crate::multipart::Form>,
41 pub(crate) timeout: Option<Duration>,
42 pub(crate) retry: Option<RetryPolicy>,
43 pub(crate) auth: Option<Auth>,
44 pub(crate) cancellation: Option<CancellationToken>,
45 pub(crate) throw_on_error: bool,
46 #[cfg(feature = "json")]
47 pub(crate) json_parser: Option<JsonParserFn>,
48 #[cfg(feature = "validate")]
49 pub(crate) validate_response: bool,
50}
51
52impl<'a> RequestBuilder<'a> {
53 pub fn param(mut self, key: impl Into<String>, value: impl ToString) -> Self {
55 self.params.insert(key.into(), value.to_string());
56 self
57 }
58
59 pub fn params(mut self, params: HashMap<String, String>) -> Self {
61 self.params.extend(params);
62 self
63 }
64
65 pub fn params_iter(
67 mut self,
68 params: impl IntoIterator<Item = (impl Into<String>, impl ToString)>,
69 ) -> Self {
70 for (k, v) in params {
71 self.params.insert(k.into(), v.to_string());
72 }
73 self
74 }
75
76 pub fn query(mut self, key: impl Into<String>, value: impl ToString) -> Self {
78 self.query
79 .insert(key.into(), QueryValue::Scalar(value.to_string()));
80 self
81 }
82
83 pub fn queries(mut self, query: IndexMap<String, QueryValue>) -> Self {
85 for (k, v) in query {
86 self.query.insert(k, v);
87 }
88 self
89 }
90
91 #[cfg(feature = "json")]
93 pub fn query_json<T: serde::Serialize>(
94 mut self,
95 key: impl Into<String>,
96 value: &T,
97 ) -> Result<Self> {
98 self.query
99 .insert(key.into(), QueryValue::from_serializable(value)?);
100 Ok(self)
101 }
102
103 pub fn header(mut self, key: impl AsRef<str>, value: impl AsRef<str>) -> Result<Self> {
105 let name = http::HeaderName::from_bytes(key.as_ref().as_bytes())
106 .map_err(|e| Error::Other(format!("invalid header name: {e}")))?;
107 let value = http::HeaderValue::from_str(value.as_ref())
108 .map_err(|e| Error::Other(format!("invalid header value: {e}")))?;
109 self.headers.insert(name, value);
110 Ok(self)
111 }
112
113 #[cfg(feature = "json")]
115 pub fn json<T: serde::Serialize>(mut self, body: &T) -> Result<Self> {
116 let bytes = serde_json::to_vec(body).map_err(|e| Error::Other(e.to_string()))?;
117 self.body = HttpBody::Bytes(Bytes::from(bytes));
118 if !self.headers.contains_key(http::header::CONTENT_TYPE) {
119 self.headers.insert(
120 http::header::CONTENT_TYPE,
121 http::HeaderValue::from_static("application/json"),
122 );
123 }
124 Ok(self)
125 }
126
127 pub fn body(mut self, body: impl Into<Bytes>) -> Self {
129 self.body = HttpBody::Bytes(body.into());
130 self
131 }
132
133 pub fn form<I, K, V>(mut self, fields: I) -> Self
135 where
136 I: IntoIterator<Item = (K, V)>,
137 K: AsRef<str>,
138 V: AsRef<str>,
139 {
140 let mut serializer = url::form_urlencoded::Serializer::new(String::new());
141 for (k, v) in fields {
142 serializer.append_pair(k.as_ref(), v.as_ref());
143 }
144 self.body = HttpBody::Bytes(Bytes::from(serializer.finish()));
145 if !self.headers.contains_key(http::header::CONTENT_TYPE) {
146 self.headers.insert(
147 http::header::CONTENT_TYPE,
148 http::HeaderValue::from_static("application/x-www-form-urlencoded"),
149 );
150 }
151 self
152 }
153
154 #[cfg(feature = "multipart")]
158 pub fn multipart(mut self, form: crate::multipart::Form) -> Self {
159 self.multipart = Some(form);
160 self.body = HttpBody::Empty;
161 self
162 }
163
164 pub fn timeout(mut self, timeout: Duration) -> Self {
166 self.timeout = Some(timeout);
167 self
168 }
169
170 pub fn retry(mut self, policy: RetryPolicy) -> Self {
172 self.retry = Some(policy);
173 self
174 }
175
176 pub fn auth(mut self, auth: Auth) -> Self {
178 self.auth = Some(auth);
179 self
180 }
181
182 pub fn bearer_token(mut self, token: impl Into<String>) -> Self {
184 self.auth = Some(Auth::bearer(token));
185 self
186 }
187
188 pub fn cancellation_token(mut self, token: CancellationToken) -> Self {
215 self.cancellation = Some(token);
216 self
217 }
218
219 pub fn throw_on_error(mut self, throw: bool) -> Self {
221 self.throw_on_error = throw;
222 self
223 }
224
225 #[cfg(feature = "json")]
229 pub fn json_parser<F>(mut self, f: F) -> Self
230 where
231 F: Fn(&Bytes) -> std::result::Result<serde_json::Value, String> + Send + Sync + 'static,
232 {
233 self.json_parser = Some(crate::json_parser::json_parser(f));
234 self
235 }
236
237 #[cfg(feature = "json")]
239 pub fn json_parser_fn(mut self, parser: JsonParserFn) -> Self {
240 self.json_parser = Some(parser);
241 self
242 }
243
244 pub async fn send(self) -> Result<Response> {
265 self.client.execute(self).await
266 }
267
268 #[cfg(feature = "json")]
288 #[must_use = "send the request with `.await` and handle the result"]
289 pub async fn send_json<T: serde::de::DeserializeOwned>(self) -> Result<T> {
290 self.send().await?.json::<T>().await
291 }
292
293 #[cfg(feature = "validate")]
295 pub fn validate_response(mut self, validate: bool) -> Self {
296 self.validate_response = validate;
297 self
298 }
299
300 #[cfg(feature = "validate")]
302 pub async fn send_json_validated<T>(self) -> Result<T>
303 where
304 T: serde::de::DeserializeOwned + garde::Validate,
305 T::Context: Default,
306 {
307 if !self.validate_response {
308 return self.send_json().await;
309 }
310 self.send().await?.json_validated().await
311 }
312}