rustbasic_core/support/
http_client.rs1use std::time::Duration;
2use serde::Serialize;
3use serde::de::DeserializeOwned;
4use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
5
6pub struct Http;
7
8pub struct PendingRequest {
9 method: reqwest::Method,
10 url: String,
11 headers: HeaderMap,
12 query: Option<serde_json::Value>,
13 json_body: Option<serde_json::Value>,
14 timeout: Option<Duration>,
15}
16
17pub struct Response {
18 inner: reqwest::Response,
19}
20
21impl Http {
22 pub fn get(url: &str) -> PendingRequest {
23 PendingRequest::new(reqwest::Method::GET, url)
24 }
25
26 pub fn post(url: &str) -> PendingRequest {
27 PendingRequest::new(reqwest::Method::POST, url)
28 }
29
30 pub fn put(url: &str) -> PendingRequest {
31 PendingRequest::new(reqwest::Method::PUT, url)
32 }
33
34 pub fn patch(url: &str) -> PendingRequest {
35 PendingRequest::new(reqwest::Method::PATCH, url)
36 }
37
38 pub fn delete(url: &str) -> PendingRequest {
39 PendingRequest::new(reqwest::Method::DELETE, url)
40 }
41}
42
43impl PendingRequest {
44 pub fn new(method: reqwest::Method, url: &str) -> Self {
45 Self {
46 method,
47 url: url.to_string(),
48 headers: HeaderMap::new(),
49 query: None,
50 json_body: None,
51 timeout: None,
52 }
53 }
54
55 pub fn with_headers(mut self, headers: std::collections::HashMap<String, String>) -> Self {
56 for (k, v) in headers {
57 if let (Ok(hname), Ok(hval)) = (HeaderName::from_bytes(k.as_bytes()), HeaderValue::from_str(&v)) {
58 self.headers.insert(hname, hval);
59 }
60 }
61 self
62 }
63
64 pub fn header(mut self, key: &str, value: &str) -> Self {
65 if let (Ok(hname), Ok(hval)) = (HeaderName::from_bytes(key.as_bytes()), HeaderValue::from_str(value)) {
66 self.headers.insert(hname, hval);
67 }
68 self
69 }
70
71 pub fn with_token(self, token: &str) -> Self {
72 self.header("Authorization", &format!("Bearer {}", token))
73 }
74
75 pub fn basic_auth(self, username: &str, password: Option<&str>) -> Self {
76 let auth_str = format!("{}:{}", username, password.unwrap_or(""));
77 let encoded = crate::base64::encode(auth_str.as_bytes());
78 self.header("Authorization", &format!("Basic {}", encoded))
79 }
80
81 pub fn query(mut self, query: impl Serialize) -> Self {
82 self.query = Some(serde_json::to_value(query).unwrap_or(serde_json::Value::Null));
83 self
84 }
85
86 pub fn json(mut self, body: impl Serialize) -> Self {
87 self.json_body = Some(serde_json::to_value(body).unwrap_or(serde_json::Value::Null));
88 self
89 }
90
91 pub fn timeout(mut self, duration: Duration) -> Self {
92 self.timeout = Some(duration);
93 self
94 }
95
96 pub async fn send(self) -> Result<Response, reqwest::Error> {
97 let mut client_builder = reqwest::Client::builder();
98 if let Some(t) = self.timeout {
99 client_builder = client_builder.timeout(t);
100 }
101 let client = client_builder.build()?;
102
103 let mut req_builder = client.request(self.method, &self.url);
104 req_builder = req_builder.headers(self.headers);
105
106 if let Some(q) = self.query {
107 req_builder = req_builder.query(&q);
108 }
109
110 if let Some(b) = self.json_body {
111 req_builder = req_builder.json(&b);
112 }
113
114 let resp = req_builder.send().await?;
115 Ok(Response { inner: resp })
116 }
117}
118
119impl Response {
120 pub fn status(&self) -> reqwest::StatusCode {
121 self.inner.status()
122 }
123
124 pub fn is_success(&self) -> bool {
125 self.inner.status().is_success()
126 }
127
128 pub async fn text(self) -> Result<String, reqwest::Error> {
129 self.inner.text().await
130 }
131
132 pub async fn json<T: DeserializeOwned>(self) -> Result<T, reqwest::Error> {
133 self.inner.json::<T>().await
134 }
135
136 pub async fn json_value(self) -> Result<serde_json::Value, reqwest::Error> {
137 self.inner.json::<serde_json::Value>().await
138 }
139}