1use crate::{
2 error::{Error, Result},
3 RequestWrapper,
4};
5use async_trait::async_trait;
6use std::{borrow::Cow, collections::HashMap};
7
8pub struct HttpClient;
10
11impl HttpClient {
12 pub fn builder<'a>() -> RequestBuilder<'a> {
13 RequestBuilder::new()
14 }
15}
16
17pub struct RequestBuilder<'a> {
19 url: &'a str,
20 method: &'a str,
21 headers: Option<HashMap<Cow<'a, str>, String>>,
22 query: Option<Vec<(&'a str, String)>>,
23 config: Option<HttpConfig>,
24}
25
26impl<'a> RequestBuilder<'a> {
27 pub fn new() -> Self {
28 Self {
29 url: "",
30 method: "",
31 headers: None,
32 query: None,
33 config: None,
34 }
35 }
36 pub fn url(mut self, url: &'a str) -> Self {
37 self.url = url;
38 self
39 }
40
41 pub fn method(mut self, method: &'a str) -> Self {
42 self.method = method;
43 self
44 }
45
46 pub fn config(mut self, config: HttpConfig) -> Self {
47 self.config = Some(config);
48 self
49 }
50
51 pub fn headers(mut self, headers: HashMap<Cow<'a, str>, String>) -> Self {
52 self.headers = Some(headers);
53 self
54 }
55
56 pub fn query(mut self, query: Vec<(&'a str, String)>) -> Self {
57 self.query = Some(query);
58 self
59 }
60
61 pub fn build(self) -> Result<RequestWrapper> {
62 let mut request = match self.config {
63 Some(config) => RequestWrapper::build_with_config(self.url, self.method, config)?,
64 None => RequestWrapper::build_default(self.url, self.method)?,
65 };
66 if let Some(header_map) = self.headers {
67 request = request.headers(header_map);
68 }
69 if let Some(query_vec) = self.query {
70 request = request.query(query_vec);
71 }
72 Ok(request)
73 }
74}
75
76pub struct HttpConfig {
78 pub connect_timeout: Option<u64>,
79 pub timeout: Option<u64>,
80}
81
82impl HttpConfig {
83 pub fn from_map(config_map: HashMap<&str, String>) -> Result<Self> {
84 let mut config = HttpConfig {
85 connect_timeout: None,
86 timeout: None,
87 };
88 if let Some(connect_timeout) = config_map.get("connect_timeout") {
89 config.connect_timeout = Some(connect_timeout.parse::<u64>().map_err(Error::config)?);
90 }
91 if let Some(timeout) = config_map.get("timeout") {
92 config.timeout = Some(timeout.parse::<u64>().map_err(Error::config)?);
93 }
94 Ok(config)
95 }
96}
97
98pub trait HttpRequest {
100 fn headers(self, headers: HashMap<Cow<str>, String>) -> Self;
101
102 fn query(self, query: Vec<(&str, String)>) -> Self;
103}
104
105#[async_trait]
107pub trait HttpResponse {
108 fn status(&self) -> http::StatusCode;
109
110 async fn none(self) -> Result<()>;
111
112 async fn text(self) -> Result<String>;
113
114 async fn vec(self) -> Result<Vec<u8>>;
115}