1use std::collections::HashMap;
2use std::time::Duration;
3
4use bytes::Bytes;
5use http::{HeaderMap, Method};
6use indexmap::IndexMap;
7
8use crate::auth::Auth;
9use crate::backend::HttpBody;
10use crate::cancel::CancellationToken;
11use crate::client::Client;
12use crate::error::Error;
13use crate::response::Response;
14use crate::retry::RetryPolicy;
15use crate::url_build::QueryValue;
16use crate::Result;
17
18#[cfg(feature = "json")]
19use crate::json_parser::JsonParserFn;
20
21pub struct RequestBuilder<'a> {
23 pub(crate) client: &'a Client,
24 pub(crate) method: Method,
25 pub(crate) path: String,
26 pub(crate) params: HashMap<String, String>,
27 pub(crate) query: IndexMap<String, QueryValue>,
28 pub(crate) headers: HeaderMap,
29 pub(crate) body: HttpBody,
30 #[cfg(feature = "multipart")]
31 pub(crate) multipart: Option<crate::multipart::Form>,
32 pub(crate) timeout: Option<Duration>,
33 pub(crate) retry: Option<RetryPolicy>,
34 pub(crate) auth: Option<Auth>,
35 pub(crate) cancellation: Option<CancellationToken>,
36 pub(crate) throw_on_error: bool,
37 #[cfg(feature = "json")]
38 pub(crate) json_parser: Option<JsonParserFn>,
39 #[cfg(feature = "validate")]
40 pub(crate) validate_response: bool,
41}
42
43impl<'a> RequestBuilder<'a> {
44 pub fn param(mut self, key: impl Into<String>, value: impl ToString) -> Self {
45 self.params.insert(key.into(), value.to_string());
46 self
47 }
48
49 pub fn params(mut self, params: HashMap<String, String>) -> Self {
50 self.params.extend(params);
51 self
52 }
53
54 pub fn params_iter(
55 mut self,
56 params: impl IntoIterator<Item = (impl Into<String>, impl ToString)>,
57 ) -> Self {
58 for (k, v) in params {
59 self.params.insert(k.into(), v.to_string());
60 }
61 self
62 }
63
64 pub fn query(mut self, key: impl Into<String>, value: impl ToString) -> Self {
65 self.query
66 .insert(key.into(), QueryValue::Scalar(value.to_string()));
67 self
68 }
69
70 pub fn queries(mut self, query: IndexMap<String, QueryValue>) -> Self {
72 for (k, v) in query {
73 self.query.insert(k, v);
74 }
75 self
76 }
77
78 #[cfg(feature = "json")]
79 pub fn query_json<T: serde::Serialize>(
80 mut self,
81 key: impl Into<String>,
82 value: &T,
83 ) -> Result<Self> {
84 self.query
85 .insert(key.into(), QueryValue::from_serializable(value)?);
86 Ok(self)
87 }
88
89 pub fn header(mut self, key: impl AsRef<str>, value: impl AsRef<str>) -> Result<Self> {
90 let name = http::HeaderName::from_bytes(key.as_ref().as_bytes())
91 .map_err(|e| Error::Other(format!("invalid header name: {e}")))?;
92 let value = http::HeaderValue::from_str(value.as_ref())
93 .map_err(|e| Error::Other(format!("invalid header value: {e}")))?;
94 self.headers.insert(name, value);
95 Ok(self)
96 }
97
98 #[cfg(feature = "json")]
99 pub fn json<T: serde::Serialize>(mut self, body: &T) -> Result<Self> {
100 let bytes = serde_json::to_vec(body).map_err(|e| Error::Other(e.to_string()))?;
101 self.body = HttpBody::Bytes(Bytes::from(bytes));
102 if !self.headers.contains_key(http::header::CONTENT_TYPE) {
103 self.headers.insert(
104 http::header::CONTENT_TYPE,
105 http::HeaderValue::from_static("application/json"),
106 );
107 }
108 Ok(self)
109 }
110
111 pub fn body(mut self, body: impl Into<Bytes>) -> Self {
112 self.body = HttpBody::Bytes(body.into());
113 self
114 }
115
116 pub fn form<I, K, V>(mut self, fields: I) -> Self
118 where
119 I: IntoIterator<Item = (K, V)>,
120 K: AsRef<str>,
121 V: AsRef<str>,
122 {
123 let mut serializer = url::form_urlencoded::Serializer::new(String::new());
124 for (k, v) in fields {
125 serializer.append_pair(k.as_ref(), v.as_ref());
126 }
127 self.body = HttpBody::Bytes(Bytes::from(serializer.finish()));
128 if !self.headers.contains_key(http::header::CONTENT_TYPE) {
129 self.headers.insert(
130 http::header::CONTENT_TYPE,
131 http::HeaderValue::from_static("application/x-www-form-urlencoded"),
132 );
133 }
134 self
135 }
136
137 #[cfg(feature = "multipart")]
139 pub fn multipart(mut self, form: crate::multipart::Form) -> Self {
140 self.multipart = Some(form);
141 self.body = HttpBody::Empty;
142 self
143 }
144
145 pub fn timeout(mut self, timeout: Duration) -> Self {
146 self.timeout = Some(timeout);
147 self
148 }
149
150 pub fn retry(mut self, policy: RetryPolicy) -> Self {
151 self.retry = Some(policy);
152 self
153 }
154
155 pub fn auth(mut self, auth: Auth) -> Self {
156 self.auth = Some(auth);
157 self
158 }
159
160 pub fn bearer_token(mut self, token: impl Into<String>) -> Self {
161 self.auth = Some(Auth::bearer(token));
162 self
163 }
164
165 pub fn cancellation_token(mut self, token: CancellationToken) -> Self {
167 self.cancellation = Some(token);
168 self
169 }
170
171 pub fn throw_on_error(mut self, throw: bool) -> Self {
173 self.throw_on_error = throw;
174 self
175 }
176
177 #[cfg(feature = "json")]
179 pub fn json_parser<F>(mut self, f: F) -> Self
180 where
181 F: Fn(&Bytes) -> std::result::Result<serde_json::Value, String> + Send + Sync + 'static,
182 {
183 self.json_parser = Some(crate::json_parser::json_parser(f));
184 self
185 }
186
187 #[cfg(feature = "json")]
189 pub fn json_parser_fn(mut self, parser: JsonParserFn) -> Self {
190 self.json_parser = Some(parser);
191 self
192 }
193
194 pub async fn send(self) -> Result<Response> {
195 self.client.execute(self).await
196 }
197
198 #[cfg(feature = "json")]
199 #[must_use = "send the request with `.await` and handle the result"]
200 pub async fn send_json<T: serde::de::DeserializeOwned>(self) -> Result<T> {
201 self.send().await?.json::<T>().await
202 }
203
204 #[cfg(feature = "validate")]
206 pub fn validate_response(mut self, validate: bool) -> Self {
207 self.validate_response = validate;
208 self
209 }
210
211 #[cfg(feature = "validate")]
213 pub async fn send_json_validated<T>(self) -> Result<T>
214 where
215 T: serde::de::DeserializeOwned + garde::Validate,
216 T::Context: Default,
217 {
218 if !self.validate_response {
219 return self.send_json().await;
220 }
221 self.send().await?.json_validated().await
222 }
223}