feignhttp/reqwest/
http.rs

1#[cfg(feature = "log")]
2use super::log::{print_request_log, print_response_log};
3use crate::{
4    error::{Error, ErrorKind, Result},
5    http::{HttpConfig, HttpRequest, HttpResponse},
6    map,
7};
8use async_trait::async_trait;
9use http::StatusCode;
10use reqwest::{Body, Client, Method, RequestBuilder, Response};
11use std::str::FromStr;
12use std::time::Duration;
13use std::{borrow::Cow, collections::HashMap};
14use url::Url;
15
16/// A wrapper of HTTP request.
17pub struct RequestWrapper {
18    url: Url,
19    headers: HashMap<String, String>,
20    request: RequestBuilder,
21}
22
23/// A wrapper of HTTP response.
24pub struct ResponseWrapper {
25    response: Response,
26}
27
28impl HttpRequest for RequestWrapper {
29    fn headers(mut self, headers: HashMap<Cow<str>, String>) -> Self {
30        for (k, v) in headers {
31            self.headers.insert(k.to_lowercase(), v);
32        }
33        self
34    }
35
36    fn query(mut self, query: Vec<(&str, String)>) -> Self {
37        if query.len() == 0 {
38            return self;
39        }
40        let mut request = self.request;
41        request = request.query(query.as_slice());
42        if let Some(builder) = request.try_clone() {
43            if let Ok(ref req) = builder.build() {
44                // Change url after add query parameters.
45                self.url = req.url().clone();
46            }
47        }
48        self.request = request;
49        self
50    }
51}
52
53impl RequestWrapper {
54    pub fn build_default(url: &str, method: &str) -> Result<RequestWrapper> {
55        let url = Url::from_str(url).map_err(Error::build)?;
56        let request = Client::new().request(
57            Method::from_str(method.to_uppercase().as_str()).map_err(Error::build)?,
58            url.clone(),
59        );
60        Ok(RequestWrapper {
61            url,
62            headers: map!(
63                "user-agent".to_string() => "Feign HTTP".to_string()),
64            request,
65        })
66    }
67
68    pub fn build_with_config(
69        url: &str,
70        method: &str,
71        config: HttpConfig,
72    ) -> Result<RequestWrapper> {
73        let mut client = Client::builder();
74        if let Some(millisecond) = config.connect_timeout {
75            client = client.connect_timeout(Duration::from_millis(millisecond));
76        }
77        if let Some(millisecond) = config.timeout {
78            client = client.timeout(Duration::from_millis(millisecond));
79        }
80        let url = Url::from_str(url).map_err(Error::build)?;
81        let request = client.build().map_err(Error::build)?.request(
82            Method::from_str(method.to_uppercase().as_str()).map_err(Error::build)?,
83            url.clone(),
84        );
85        Ok(RequestWrapper {
86            url,
87            headers: map!(
88                "user-agent".to_string() => "Feign HTTP".to_string()),
89            request,
90        })
91    }
92
93    fn set_header(mut self) -> Self {
94        let mut request = self.request;
95        for (k, v) in &self.headers {
96            request = request.header(k.as_str(), v);
97        }
98        self.request = request;
99        self
100    }
101
102    fn set_header_if_absent(&mut self, k: &str, v: String) {
103        if let None = self.headers.get(k) {
104            self.headers.insert(k.to_string(), v);
105        }
106    }
107
108    async fn send_body(self, body: Option<Body>) -> Result<ResponseWrapper> {
109        let url = self.url.clone();
110        let mut request = self.set_header().request;
111
112        if let Some(body) = body {
113            request = request.body(body);
114        }
115
116        #[cfg(feature = "log")]
117        print_request_log(request.try_clone().unwrap());
118
119        return match request.send().await {
120            Ok(response) => {
121                #[cfg(feature = "log")]
122                print_response_log(&response);
123
124                let status = response.status();
125
126                // Client or server error.
127                if status.is_client_error() || status.is_server_error() {
128                    return Err(Error::status(url, status));
129                }
130
131                Ok(ResponseWrapper { response })
132            }
133            Err(e) => Err(Error::new(ErrorKind::Request, Some(e))),
134        };
135    }
136
137    pub async fn send(self) -> Result<ResponseWrapper> {
138        self.send_body(None).await
139    }
140
141    pub async fn send_text(mut self, text: String) -> Result<ResponseWrapper> {
142        self.set_header_if_absent("content-type", "text/plain".to_string());
143        self.send_body(Some(Body::from(text))).await
144    }
145
146    pub async fn send_form<T>(mut self, form: &T) -> Result<ResponseWrapper>
147    where
148        T: serde::ser::Serialize,
149    {
150        self.set_header_if_absent(
151            "content-type",
152            "application/x-www-form-urlencoded".to_string(),
153        );
154        let form = serde_urlencoded::to_string(form).map_err(Error::encode)?;
155        self.send_body(Some(Body::from(form))).await
156    }
157
158    #[cfg(feature = "json")]
159    pub async fn send_json<T>(mut self, json: &T) -> Result<ResponseWrapper>
160    where
161        T: serde::ser::Serialize,
162    {
163        self.set_header_if_absent("content-type", "application/json".to_string());
164        let json = serde_json::to_string(json).map_err(Error::encode)?;
165        self.send_body(Some(Body::from(json))).await
166    }
167
168    pub async fn send_vec(mut self, vec: Vec<u8>) -> Result<ResponseWrapper> {
169        self.set_header_if_absent("content-type", "application/octet-stream".to_string());
170        self.send_body(Some(Body::from(vec))).await
171    }
172}
173
174#[async_trait]
175impl HttpResponse for ResponseWrapper {
176    fn status(&self) -> StatusCode {
177        self.response.status()
178    }
179
180    async fn none(self) -> Result<()> {
181        Ok(())
182    }
183
184    async fn text(self) -> Result<String> {
185        self.response.text().await.map_err(Error::decode)
186    }
187
188    async fn vec(self) -> Result<Vec<u8>> {
189        let by = self.response.bytes().await.map_err(Error::decode)?;
190        Ok(by.to_vec())
191    }
192}
193
194impl ResponseWrapper {
195    #[cfg(feature = "json")]
196    pub async fn json<T>(self) -> Result<T>
197    where
198        T: serde::de::DeserializeOwned,
199    {
200        self.response.json::<T>().await.map_err(Error::decode)
201    }
202}