asknothingx2_util/api/
header_builder.rs

1use http::{
2    header::{
3        ACCEPT, ACCEPT_ENCODING, ACCEPT_LANGUAGE, ACCESS_CONTROL_ALLOW_HEADERS,
4        ACCESS_CONTROL_ALLOW_METHODS, ACCESS_CONTROL_ALLOW_ORIGIN, AUTHORIZATION, CACHE_CONTROL,
5        CONNECTION, CONTENT_LENGTH, CONTENT_TYPE, ORIGIN, REFERER, USER_AGENT,
6    },
7    HeaderMap, HeaderName, HeaderValue,
8};
9
10use super::{
11    content_type::{Application, Multipart, Text},
12    request::HeaderError,
13    AuthScheme,
14};
15
16mod headers {
17    use http::HeaderName;
18
19    pub const CLIENT_ID: HeaderName = HeaderName::from_static("client-id");
20    pub const X_API_KEY: HeaderName = HeaderName::from_static("x-api-key");
21    pub const X_REQUEST_ID: HeaderName = HeaderName::from_static("x-request-id");
22}
23
24#[derive(Debug)]
25pub struct HeaderBuilder {
26    _inner: HeaderMap,
27}
28
29#[allow(clippy::new_without_default)]
30impl HeaderBuilder {
31    pub fn new() -> Self {
32        Self {
33            _inner: HeaderMap::new(),
34        }
35    }
36
37    pub fn with_capacity(capacity: usize) -> Self {
38        Self {
39            _inner: HeaderMap::with_capacity(capacity),
40        }
41    }
42
43    pub fn header(&mut self, key: HeaderName, value: HeaderValue) -> &mut Self {
44        self._inner.insert(key, value);
45        self
46    }
47
48    pub fn header_static(&mut self, key: HeaderName, value: &'static str) -> &mut Self {
49        self._inner.insert(key, HeaderValue::from_static(value));
50        self
51    }
52
53    pub fn header_str(&mut self, key: HeaderName, value: &str) -> Result<&mut Self, HeaderError> {
54        let val = HeaderValue::from_str(value).map_err(|e| HeaderError::InvalidHeaderValue {
55            name: key.to_string(),
56            value: value.to_string(),
57            reason: e.to_string(),
58        })?;
59
60        self._inner.insert(key, val);
61        Ok(self)
62    }
63
64    pub fn append(
65        &mut self,
66        key: HeaderName,
67        value: HeaderValue,
68    ) -> Result<&mut Self, http::Error> {
69        self._inner.append(key, value);
70
71        Ok(self)
72    }
73
74    /// Client-Id: <id>
75    pub fn client_id(&mut self, id: &str) -> Result<&mut Self, HeaderError> {
76        self.header_str(headers::CLIENT_ID, id)
77    }
78
79    /// User-Agent: <agent>
80    pub fn user_agent(&mut self, agent: &str) -> Result<&mut Self, HeaderError> {
81        self.header_str(USER_AGENT, agent)
82    }
83
84    /// Cache-Control: no-cache
85    pub fn cache_control_no_cache(&mut self) -> &mut Self {
86        self._inner
87            .insert(CACHE_CONTROL, HeaderValue::from_static("no-cache"));
88        self
89    }
90
91    /// Cache-Control: <value>
92    pub fn cache_control(&mut self, value: &str) -> Result<&mut Self, HeaderError> {
93        self.header_str(CACHE_CONTROL, value)
94    }
95
96    /// X-API-Key: <key>
97    pub fn api_key(&mut self, key: &str) -> Result<&mut Self, HeaderError> {
98        self.header_str(headers::X_API_KEY, key)
99    }
100
101    /// X-Request-ID: <id>
102    pub fn request_id(&mut self, id: &str) -> Result<&mut Self, HeaderError> {
103        self.header_str(headers::X_REQUEST_ID, id)
104    }
105
106    /// Origin: <origin>
107    pub fn origin(&mut self, origin: &str) -> Result<&mut Self, HeaderError> {
108        self.header_str(ORIGIN, origin)
109    }
110
111    /// Referer: <referer>
112    pub fn referer(&mut self, referer: &str) -> Result<&mut Self, HeaderError> {
113        self.header_str(REFERER, referer)
114    }
115
116    // CORS headers
117    /// Access-Control-Allow-Origin: *
118    pub fn cors_allow_all(&mut self) -> &mut Self {
119        self._inner
120            .insert(ACCESS_CONTROL_ALLOW_ORIGIN, HeaderValue::from_static("*"));
121        self
122    }
123
124    /// Access-Control-Allow-Origin: <origin>
125    pub fn cors_allow_origin(&mut self, origin: &str) -> Result<&mut Self, HeaderError> {
126        self.header_str(ACCESS_CONTROL_ALLOW_ORIGIN, origin)
127    }
128
129    /// Access-Control-Allow-Methods: GET, POST, PUT, DELETE
130    pub fn cors_allow_methods_standard(&mut self) -> &mut Self {
131        self._inner.insert(
132            ACCESS_CONTROL_ALLOW_METHODS,
133            HeaderValue::from_static("GET,POST,PUT,DELETE"),
134        );
135        self
136    }
137
138    /// Access-Control-Allow-Headers: Content-Type, Authorization
139    pub fn cors_allow_headers_standard(&mut self) -> &mut Self {
140        self._inner.insert(
141            ACCESS_CONTROL_ALLOW_HEADERS,
142            HeaderValue::from_static("Content-Type,Authorization"),
143        );
144        self
145    }
146
147    /// Connection: keep-alive
148    pub fn connection_keep_alive(&mut self) -> &mut Self {
149        self._inner
150            .insert(CONNECTION, HeaderValue::from_static("keep-alive"));
151        self
152    }
153
154    /// Connection: close
155    pub fn connection_close(&mut self) -> &mut Self {
156        self._inner
157            .insert(CONNECTION, HeaderValue::from_static("close"));
158        self
159    }
160
161    /// Content-Length: <length>
162    pub fn content_length(&mut self, length: u64) -> &mut Self {
163        self._inner.insert(
164            CONTENT_LENGTH,
165            HeaderValue::from_str(&length.to_string()).unwrap(),
166        );
167        self
168    }
169
170    /// Accept: application/json, Content-Type: application/json
171    pub fn json_api(&mut self) -> &mut Self {
172        self.accept_json().content_type_json()
173    }
174
175    pub fn build(self) -> HeaderMap {
176        self._inner
177    }
178}
179
180impl HeaderBuilder {
181    /// ACCEPT: application/json
182    pub fn accept_json(&mut self) -> &mut Self {
183        self._inner
184            .insert(ACCEPT, Application::Json.to_header_value());
185        self
186    }
187
188    /// ACCEPT: text/html
189    pub fn accept_html(&mut self) -> &mut Self {
190        self._inner.insert(ACCEPT, Text::Html.to_header_value());
191        self
192    }
193
194    /// ACCEPT: text/plain
195    pub fn accept_text(&mut self) -> &mut Self {
196        self._inner
197            .insert(ACCEPT, HeaderValue::from_static("text/plain"));
198        self
199    }
200
201    /// ACCEPT: */*
202    pub fn accept_any(&mut self) -> &mut Self {
203        self._inner.insert(ACCEPT, HeaderValue::from_static("*/*"));
204        self
205    }
206
207    /// ACCEPT: multi items
208    pub fn accept_mulity(&mut self, items: &[&str]) -> Result<&mut Self, HeaderError> {
209        self.header_str(ACCEPT, &items.join(","))
210    }
211
212    /// Accept-Encoding: gzip, deflate, br
213    pub fn accept_encoding_standard(&mut self) -> &mut Self {
214        self._inner
215            .insert(ACCEPT_ENCODING, HeaderValue::from_static("gzip,deflate,br"));
216        self
217    }
218
219    /// Accept-Language: en-US, en;q=0.9
220    pub fn accept_language_en(&mut self) -> &mut Self {
221        self._inner
222            .insert(ACCEPT_LANGUAGE, HeaderValue::from_static("en-US,en;q=0.9"));
223        self
224    }
225
226    /// Accept-Language: <lang>
227    pub fn accept_language(&mut self, lang: &str) -> Result<&mut Self, HeaderError> {
228        self.header_str(ACCEPT_LANGUAGE, lang)
229    }
230}
231
232impl HeaderBuilder {
233    /// CONTENT-TYPE: application/x-www-form-urlencoded
234    pub fn content_type_formencoded(&mut self) -> &mut Self {
235        self._inner
236            .insert(CONTENT_TYPE, Application::FormUrlEncoded.to_header_value());
237        self
238    }
239
240    /// CONTENT-TYPE: application/json
241    pub fn content_type_json(&mut self) -> &mut Self {
242        self._inner
243            .insert(CONTENT_TYPE, Application::Json.to_header_value());
244        self
245    }
246
247    /// CONTENT-TYPE: text/plain
248    pub fn content_type_text(&mut self) -> &mut Self {
249        self._inner
250            .insert(CONTENT_TYPE, Text::Plain.to_header_value());
251        self
252    }
253
254    /// CONTENT-TYPE: text/html
255    pub fn content_type_html(&mut self) -> &mut Self {
256        self._inner
257            .insert(CONTENT_TYPE, Text::Html.to_header_value());
258        self
259    }
260
261    /// CONTENT-TYPE: multipart/form-data
262    pub fn content_type_multipart(&mut self) -> &mut Self {
263        self._inner
264            .insert(CONTENT_TYPE, Multipart::FormData.to_header_value());
265        self
266    }
267}
268
269impl HeaderBuilder {
270    /// Authorization: <type> <credentials>
271    pub fn authorization(&mut self, auth: AuthScheme) -> &mut Self {
272        self._inner
273            .insert(AUTHORIZATION, auth.to_header_value().unwrap());
274        self
275    }
276
277    pub fn basic_auth(&mut self, username: &str, password: &str) -> &mut Self {
278        self.authorization(AuthScheme::basic(username, password))
279    }
280
281    pub fn bearer_token(&mut self, token: &str) -> &mut Self {
282        self.authorization(AuthScheme::bearer(token))
283    }
284}