Skip to main content

http_request/request/request_builder/
struct.rs

1use super::*;
2
3/// Fluent builder for [`HttpRequest`].
4///
5/// Single-purpose, chainable. Each method returns `&mut Self` for fluent
6/// chaining; call [`RequestBuilder::build`] to obtain the final
7/// [`HttpRequest`].
8///
9/// # Examples
10///
11/// ```ignore
12/// use http_request::{RequestBuilder, Proxy};
13///
14/// // sync GET
15/// let mut req = RequestBuilder::new()
16///     .get("https://example.com/api")
17///     .header("Accept", "application/json")
18///     .timeout(5_000)
19///     .build();
20/// let _resp = req.send();
21///
22/// // async POST with JSON body
23/// let req = RequestBuilder::new()
24///     .post("https://example.com/api")
25///     .body_json(&serde_json::json!({"k": "v"}))
26///     .header("Content-Type", "application/json")
27///     .proxy(Proxy::https("127.0.0.1", 7890).auth("u", "p"))
28///     .build();
29/// let _resp = req.send_async().await;
30/// ```
31#[derive(Clone, Data, Debug, Default)]
32pub struct RequestBuilder {
33    #[get(pub(crate))]
34    #[get_mut(pub(crate))]
35    #[set(pub(crate))]
36    request: HttpRequest,
37}
38
39impl RequestBuilder {
40    /// Returns the underlying request mutably.
41    ///
42    /// # Returns
43    ///
44    /// - `&mut HttpRequest` - The mutable request being built.
45    pub fn get_request_mut(&mut self) -> &mut HttpRequest {
46        &mut self.request
47    }
48
49    /// Create an empty builder (defaults: GET, no headers, default config).
50    pub fn new() -> Self {
51        Self::default()
52    }
53
54    /// Shortcut for `method(Method::Get)` + `url(url)`.
55    pub fn get(&mut self, url: impl Into<String>) -> &mut Self {
56        self.get_mut_request().set_method(Method::Get);
57        self.get_mut_request().set_url(url);
58        self
59    }
60
61    /// Shortcut for `method(Method::Post)` + `url(url)`.
62    pub fn post(&mut self, url: impl Into<String>) -> &mut Self {
63        self.get_mut_request().set_method(Method::Post);
64        self.get_mut_request().set_url(url);
65        self
66    }
67
68    /// Set HTTP method explicitly (`Method::Get` / `Method::Post` / etc.).
69    pub fn method(&mut self, method: Method) -> &mut Self {
70        self.get_mut_request().set_method(method);
71        self
72    }
73
74    /// Set URL.
75    pub fn url(&mut self, url: impl Into<String>) -> &mut Self {
76        self.get_mut_request().set_url(url);
77        self
78    }
79
80    /// Set a single header (last write wins on duplicate keys).
81    pub fn header<K: AsRef<str>, V: AsRef<str>>(&mut self, key: K, value: V) -> &mut Self {
82        self.get_mut_request().set_header(key, value);
83        self
84    }
85
86    /// Set many headers at once.
87    pub fn headers<K, V>(&mut self, headers: HashMap<K, V>) -> &mut Self
88    where
89        K: AsRef<str>,
90        V: AsRef<str>,
91    {
92        for (k, v) in headers {
93            self.get_mut_request().set_header(k, v);
94        }
95        self
96    }
97
98    /// Remove a header by key.
99    pub fn remove_header<K: AsRef<str>>(&mut self, key: K) -> &mut Self {
100        self.get_mut_request().remove_header(key);
101        self
102    }
103
104    /// Clear all headers.
105    pub fn clear_headers(&mut self) -> &mut Self {
106        self.get_mut_request().clear_headers();
107        self
108    }
109
110    /// Set raw body bytes.
111    pub fn body<B: Into<Vec<u8>>>(&mut self, bytes: B) -> &mut Self {
112        self.get_mut_request().set_body(Body::from_bytes(bytes));
113        self
114    }
115
116    /// Set UTF-8 text body (will be encoded per `Content-Type` on send).
117    pub fn body_text<T: Into<String>>(&mut self, text: T) -> &mut Self {
118        self.get_mut_request()
119            .set_body(Body::from_bytes(text.into().into_bytes()));
120        self
121    }
122
123    /// Set JSON body (serialised via `serde_json`).
124    pub fn body_json<V: serde::Serialize>(&mut self, value: &V) -> &mut Self {
125        if let Ok(bytes) = serde_json::to_vec(value) {
126            self.get_mut_request().set_body(Body::from_bytes(bytes));
127        }
128        self
129    }
130
131    /// Set request timeout in milliseconds.
132    pub fn timeout(&mut self, ms: u64) -> &mut Self {
133        self.get_mut_request().get_config_mut().set_timeout(ms);
134        self
135    }
136
137    /// Set per-read buffer size.
138    pub fn buffer_size(&mut self, n: usize) -> &mut Self {
139        self.get_mut_request().get_config_mut().set_buffer_size(n);
140        self
141    }
142
143    /// Force HTTP/1.1.
144    pub fn http1_1_only(&mut self) -> &mut Self {
145        self.get_mut_request()
146            .get_config_mut()
147            .set_http_version(HttpVersion::Http1_1);
148        self
149    }
150
151    /// Force HTTP/2.
152    pub fn http2_only(&mut self) -> &mut Self {
153        self.get_mut_request()
154            .get_config_mut()
155            .set_http_version(HttpVersion::Http2);
156        self
157    }
158
159    /// Enable auto-follow of 3xx redirects.
160    pub fn redirect(&mut self) -> &mut Self {
161        self.get_mut_request().get_config_mut().set_redirect(true);
162        self
163    }
164
165    /// Disable auto-follow of 3xx redirects (default).
166    pub fn no_redirect(&mut self) -> &mut Self {
167        self.get_mut_request().get_config_mut().set_redirect(false);
168        self
169    }
170
171    /// Maximum number of redirects to follow (default `DEFAULT_MAX_REDIRECT_TIMES`).
172    pub fn max_redirect_times(&mut self, n: usize) -> &mut Self {
173        self.get_mut_request()
174            .get_config_mut()
175            .set_max_redirect_times(n);
176        self
177    }
178
179    /// Enable automatic response body decompression (gzip / deflate / br).
180    pub fn decode(&mut self) -> &mut Self {
181        self.get_mut_request().get_config_mut().set_decode(true);
182        self
183    }
184
185    /// Disable automatic response body decompression.
186    pub fn no_decode(&mut self) -> &mut Self {
187        self.get_mut_request().get_config_mut().set_decode(false);
188        self
189    }
190
191    /// Set the proxy configuration. Pass `None` (via [`Proxy::default()`) to
192    /// clear an existing proxy.
193    ///
194    /// Construct via [`Proxy::http`] / [`Proxy::https`] / [`Proxy::socks5`]
195    /// and optionally chain `.auth(user, pass)`.
196    pub fn proxy(&mut self, proxy: Proxy) -> &mut Self {
197        self.get_mut_request()
198            .get_config_mut()
199            .set_proxy(Some(proxy));
200        self
201    }
202
203    /// Clear the proxy (use direct connection).
204    pub fn no_proxy(&mut self) -> &mut Self {
205        self.get_mut_request().get_config_mut().set_proxy(None);
206        self
207    }
208
209    /// Finalise the builder and return the [`HttpRequest`].
210    pub fn build(&mut self) -> HttpRequest {
211        std::mem::take(self.get_mut_request())
212    }
213}