1use std::collections::HashMap;
2use std::time::Duration;
3use base64::Engine;
4use base64::prelude::BASE64_STANDARD;
5use http::{HeaderMap, HeaderName, HeaderValue};
6use http::header::{AUTHORIZATION, CONTENT_TYPE};
7use serde::Serialize;
8use crate::client::response::{ClientixError, ClientixErrorData, ClientixResult};
9use crate::core::headers::content_type::ContentType;
10
11#[derive(Clone, Debug, Default)]
12pub struct RequestConfig {
13 path: String,
14 headers: HeaderMap,
15 queries: Vec<(String, String)>,
16 body: Option<String>,
17 timeout: Option<Duration>
18}
19
20pub trait ClientixRequestBuilder {
21
22 fn config(&mut self) -> &mut RequestConfig;
23
24 fn result(&mut self) -> &mut ClientixResult<()>;
25
26 fn path(mut self, path: &str) -> Self where Self: Sized {
27 self.config().set_path(path);
28 self
29 }
30
31 fn query(mut self, key: &str, value: &str) -> Self where Self: Sized {
32 self.config().add_query(key, value);
33 self
34 }
35
36 fn queries(mut self, queries: HashMap<String, String>) -> Self where Self: Sized {
37 for (key, value) in queries {
38 self = self.query(key.as_str(), value.as_str());
39 }
40
41 self
42 }
43
44 fn header(mut self, key: &str, value: &str) -> Self where Self: Sized {
45 self.config().set_header(key, value, false);
46 self
47 }
48
49 fn headers(mut self, headers: HashMap<String, String>) -> Self where Self: Sized {
50 for (key, value) in headers {
51 self = self.header(key.as_str(), value.as_str());
52 }
53
54 self
55 }
56
57 fn basic_auth(mut self, username: &str, password: &str) -> Self where Self: Sized {
58 self.config().basic_auth(username, password);
59 self
60 }
61
62 fn bearer_auth(mut self, token: &str) -> Self where Self: Sized {
63 self.config().bearer_auth(token);
64 self
65 }
66
67 fn body<T: Serialize>(mut self, body: T, content_type: ContentType) -> Self where Self: Sized {
68 *self.result() = self.config().set_body(body, content_type);
69 self
70 }
71
72}
73
74impl RequestConfig {
75
76 pub fn new() -> Self {
77 RequestConfig {
78 path: Default::default(),
79 headers: Default::default(),
80 queries: Default::default(),
81 body: None,
82 timeout: None,
83 }
84 }
85
86 pub fn get_path(&self) -> &String {
87 &self.path
88 }
89
90 pub fn set_path(&mut self, path: &str) {
91 self.path = path.to_string();
92 }
93
94 pub fn get_queries(&self) -> &Vec<(String, String)> {
95 &self.queries
96 }
97
98 pub fn add_query(&mut self, key: &str, value: &str) {
99 self.queries.push((key.to_string(), value.to_string()));
100 }
101
102 pub fn add_queries(&mut self, queries: HashMap<String, String>) {
103 for (key, value) in queries {
104 self.queries.push((key, value));
105 }
106 }
107
108 pub fn set_queries(&mut self, queries: HashMap<String, String>) {
109 self.queries.clear();
110
111 for (key, value) in queries {
112 self.queries.push((key, value));
113 }
114 }
115
116 pub fn get_headers(&self) -> &HeaderMap {
117 &self.headers
118 }
119
120 pub fn set_header(&mut self, key: &str, value: &str, sensitive: bool) {
121 let header_name = if let Ok(name) = HeaderName::from_bytes(key.as_bytes()) {
122 name
123 } else {
124 return;
125 };
126
127 let mut header_value = if let Ok(value) = HeaderValue::from_str(&value) {
128 value
129 } else {
130 return;
131 };
132
133 header_value.set_sensitive(sensitive);
134
135 self.headers.insert(header_name, header_value);
136 }
137
138 pub fn set_headers(&mut self, headers: HashMap<String, String>) {
139 for (key, value) in headers {
140 self.set_header(key.as_str(), value.as_str(), false);
141 }
142 }
143
144 pub fn basic_auth(&mut self, username: &str, password: &str) {
145 let basic_token = format!("Basic {}", BASE64_STANDARD.encode(format!("{username}:{password}")));
146 self.set_header(AUTHORIZATION.as_str(), basic_token.as_str(), true);
147 }
148
149 pub fn bearer_auth(&mut self, token: &str) {
150 self.set_header(AUTHORIZATION.as_str(), format!("Bearer {}", token).as_str(), true);
151 }
152
153 pub fn get_body(&self) -> &Option<String> {
154 &self.body
155 }
156
157 pub fn set_body<T: Serialize>(&mut self, body: T, content_type: ContentType) -> ClientixResult<()> {
158 match content_type {
159 ContentType::ApplicationJson => self.set_json_body(body),
160 ContentType::ApplicationXWwwFormUrlEncoded => self.set_form_body(body),
161 ContentType::ApplicationXml => self.set_xml_body(body),
162 _ => Err(ClientixError::InvalidRequest(
163 ClientixErrorData::builder()
164 .message(format!("invalid content type: {:?}", content_type).as_str())
165 .build(),
166 None
167 ))
168 }
169 }
170
171 fn set_json_body<T: Serialize>(&mut self, body: T) -> ClientixResult<()> {
172 match serde_json::to_string(&body) {
173 Ok(body) => {
174 self.body = Some(body);
175 self.headers.insert(CONTENT_TYPE, ContentType::ApplicationJson.try_into().unwrap());
176 Ok(())
177 },
178 Err(err) => Err(ClientixError::InvalidRequest(Default::default(), Some(err.into())))
179 }
180 }
181
182 fn set_xml_body<T: Serialize>(&mut self, body: T) -> ClientixResult<()> {
183 match serde_xml_rs::to_string(&body) {
184 Ok(body) => {
185 self.body = Some(body);
186 self.headers.insert(CONTENT_TYPE, ContentType::ApplicationXml.try_into().unwrap());
187 Ok(())
188 },
189 Err(err) => Err(ClientixError::InvalidRequest(Default::default(), Some(err.into())))
190 }
191 }
192
193 fn set_form_body<T: Serialize>(&mut self, body: T) -> ClientixResult<()> {
194 match serde_urlencoded::to_string(&body) {
195 Ok(body) => {
196 self.body = Some(body);
197 self.headers.insert(CONTENT_TYPE, ContentType::ApplicationXWwwFormUrlEncoded.try_into().unwrap());
198 Ok(())
199 },
200 Err(err) => Err(ClientixError::InvalidRequest(Default::default(), Some(err.into())))
201 }
202 }
203
204 pub fn get_timeout(&self) -> Option<Duration> {
205 self.timeout
206 }
207
208 pub fn set_timeout(&mut self, timeout: Duration) {
209 self.timeout = Some(timeout);
210 }
211
212}