feignhttp/
http.rs

1use crate::{
2    error::{Error, Result},
3    RequestWrapper,
4};
5use async_trait::async_trait;
6use std::{borrow::Cow, collections::HashMap};
7
8/// An HTTP client to create RequestBuilder.
9pub struct HttpClient;
10
11impl HttpClient {
12    pub fn builder<'a>() -> RequestBuilder<'a> {
13        RequestBuilder::new()
14    }
15}
16
17/// An HTTP requet builder to make requests.
18pub 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
76/// Configuration of an HTTP request.
77pub 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
98/// A trait of HTTP request.
99pub 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/// A trait of HTTP response.
106#[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}