use crate::{client::Client, enums::RequestMethod, errors::ClientError};
use reqwest::{
header::{HeaderMap, HeaderName, HeaderValue},
Method,
};
use serde_json::Value;
use std::str::FromStr;
use url::Url;
pub struct ReqwestClient {
pub http: reqwest::blocking::Client,
pub base: String,
}
impl ReqwestClient {
pub fn new(base: &str, http: reqwest::blocking::Client) -> Self {
ReqwestClient {
base: base.to_string(),
http,
}
}
pub fn default(base: &str) -> Self {
ReqwestClient {
base: base.to_string(),
http: reqwest::blocking::Client::default(),
}
}
fn build_request(
&self,
method: &RequestMethod,
url: &Url,
query: &[(String, Value)],
headers: &[(String, String)],
data: Vec<u8>,
) -> Result<reqwest::blocking::Request, ClientError> {
let builder = match method {
RequestMethod::DELETE => match data.is_empty() {
false => self.http.delete(url.as_ref()).body(data),
true => self.http.delete(url.as_ref()),
},
RequestMethod::GET => self.http.get(url.as_ref()),
RequestMethod::HEAD => match data.is_empty() {
false => self.http.head(url.as_ref()).body(data),
true => self.http.head(url.as_ref()),
},
RequestMethod::LIST => match data.is_empty() {
false => self
.http
.request(Method::from_str("LIST").unwrap(), url.as_ref())
.body(data),
true => self
.http
.request(Method::from_str("LIST").unwrap(), url.as_ref()),
},
RequestMethod::POST => match data.is_empty() {
false => self.http.post(url.as_ref()).body(data),
true => self.http.post(url.as_ref()),
},
};
let mut map = HeaderMap::new();
headers.iter().for_each(|h| {
map.insert(
HeaderName::from_str(h.0.as_str()).unwrap(),
HeaderValue::from_str(h.1.as_str()).unwrap(),
);
});
let req = builder.query(query).headers(map).build().map_err(|e| {
ClientError::RequestBuildError {
source: Box::new(e),
url: url.to_string(),
method: method.clone(),
}
})?;
Ok(req)
}
}
impl Client for ReqwestClient {
fn base(&self) -> &str {
self.base.as_str()
}
fn send(&self, req: crate::client::Request) -> Result<crate::client::Response, ClientError> {
let request =
self.build_request(&req.method, &req.url, &req.query, &req.headers, req.body)?;
let err_url = req.url;
let err_method = req.method;
let response = self
.http
.execute(request)
.map_err(|e| ClientError::RequestError {
source: Box::new(e),
url: err_url.to_string(),
method: err_method,
})?;
let url = response.url().clone();
let status_code = response.status().as_u16();
let body = response
.bytes()
.map_err(|e| ClientError::ResponseError {
source: Box::new(e),
})?
.to_vec();
Ok(crate::client::Response {
url,
code: status_code,
body,
})
}
}