1use std::collections::HashMap;
2use std::time::Duration;
3
4use bytes::Bytes;
5use http::{HeaderMap, Method};
6
7use crate::auth::Auth;
8use crate::client::Client;
9use crate::error::Error;
10use crate::response::Response;
11use crate::retry::RetryPolicy;
12use crate::url_build::QueryValue;
13use crate::Result;
14
15#[cfg(feature = "json")]
16use crate::json_parser::JsonParserFn;
17
18pub struct RequestBuilder<'a> {
20 pub(crate) client: &'a Client,
21 pub(crate) method: Method,
22 pub(crate) path: String,
23 pub(crate) params: HashMap<String, String>,
24 pub(crate) query: HashMap<String, QueryValue>,
25 pub(crate) headers: HeaderMap,
26 pub(crate) body: Option<Bytes>,
27 pub(crate) timeout: Option<Duration>,
28 pub(crate) retry: Option<RetryPolicy>,
29 pub(crate) auth: Option<Auth>,
30 #[cfg(feature = "json")]
31 pub(crate) json_parser: Option<JsonParserFn>,
32 #[cfg(feature = "validate")]
33 pub(crate) validate_response: bool,
34}
35
36impl<'a> RequestBuilder<'a> {
37 pub fn param(mut self, key: impl Into<String>, value: impl ToString) -> Self {
38 self.params.insert(key.into(), value.to_string());
39 self
40 }
41
42 pub fn params(mut self, params: HashMap<String, String>) -> Self {
43 self.params.extend(params);
44 self
45 }
46
47 pub fn params_iter(
48 mut self,
49 params: impl IntoIterator<Item = (impl Into<String>, impl ToString)>,
50 ) -> Self {
51 for (k, v) in params {
52 self.params.insert(k.into(), v.to_string());
53 }
54 self
55 }
56
57 pub fn query(mut self, key: impl Into<String>, value: impl ToString) -> Self {
58 self.query
59 .insert(key.into(), QueryValue::Scalar(value.to_string()));
60 self
61 }
62
63 #[cfg(feature = "json")]
64 pub fn query_json<T: serde::Serialize>(
65 mut self,
66 key: impl Into<String>,
67 value: &T,
68 ) -> Result<Self> {
69 self.query
70 .insert(key.into(), QueryValue::from_serializable(value)?);
71 Ok(self)
72 }
73
74 pub fn header(mut self, key: impl AsRef<str>, value: impl AsRef<str>) -> Result<Self> {
75 let name = http::HeaderName::from_bytes(key.as_ref().as_bytes())
76 .map_err(|e| Error::Other(format!("invalid header name: {e}")))?;
77 let value = http::HeaderValue::from_str(value.as_ref())
78 .map_err(|e| Error::Other(format!("invalid header value: {e}")))?;
79 self.headers.insert(name, value);
80 Ok(self)
81 }
82
83 #[cfg(feature = "json")]
84 pub fn json<T: serde::Serialize>(mut self, body: &T) -> Result<Self> {
85 let bytes = serde_json::to_vec(body).map_err(|e| Error::Other(e.to_string()))?;
86 self.body = Some(Bytes::from(bytes));
87 if !self.headers.contains_key(http::header::CONTENT_TYPE) {
88 self.headers.insert(
89 http::header::CONTENT_TYPE,
90 http::HeaderValue::from_static("application/json"),
91 );
92 }
93 Ok(self)
94 }
95
96 pub fn body(mut self, body: impl Into<Bytes>) -> Self {
97 self.body = Some(body.into());
98 self
99 }
100
101 pub fn timeout(mut self, timeout: Duration) -> Self {
102 self.timeout = Some(timeout);
103 self
104 }
105
106 pub fn retry(mut self, policy: RetryPolicy) -> Self {
107 self.retry = Some(policy);
108 self
109 }
110
111 pub fn auth(mut self, auth: Auth) -> Self {
112 self.auth = Some(auth);
113 self
114 }
115
116 pub fn bearer_token(mut self, token: impl Into<String>) -> Self {
117 self.auth = Some(Auth::bearer(token));
118 self
119 }
120
121 #[cfg(feature = "json")]
123 pub fn json_parser<F>(mut self, f: F) -> Self
124 where
125 F: Fn(&Bytes) -> std::result::Result<serde_json::Value, String> + Send + Sync + 'static,
126 {
127 self.json_parser = Some(crate::json_parser::json_parser(f));
128 self
129 }
130
131 #[cfg(feature = "json")]
133 pub fn json_parser_fn(mut self, parser: JsonParserFn) -> Self {
134 self.json_parser = Some(parser);
135 self
136 }
137
138 pub async fn send(self) -> Result<Response> {
139 self.client.execute(self).await
140 }
141
142 #[cfg(feature = "json")]
143 #[must_use = "send the request with `.await` and handle the result"]
144 pub async fn send_json<T: serde::de::DeserializeOwned>(self) -> Result<T> {
145 self.send().await?.json::<T>().await
146 }
147
148 #[cfg(feature = "validate")]
150 pub fn validate_response(mut self, validate: bool) -> Self {
151 self.validate_response = validate;
152 self
153 }
154
155 #[cfg(feature = "validate")]
157 pub async fn send_json_validated<T>(self) -> Result<T>
158 where
159 T: serde::de::DeserializeOwned + garde::Validate,
160 T::Context: Default,
161 {
162 if !self.validate_response {
163 return self.send_json().await;
164 }
165 self.send().await?.json_validated().await
166 }
167}