use crate::{error::Result, map};
use reqwest::{Body, Client, Method, RequestBuilder, Response, Url};
use std::collections::HashMap;
use std::str::FromStr;
use std::time::Duration;
pub struct HttpClient {}
impl HttpClient {
pub fn default_request(url: &str, method: &str) -> RequestWrapper {
RequestWrapper::build_default(url, method)
}
pub fn configure_request(url: &str, method: &str, config: HttpConfig) -> RequestWrapper {
RequestWrapper::build_with_config(url, method, config)
}
}
pub struct HttpConfig {
pub connect_timeout: Option<u16>,
pub timeout: Option<u16>,
}
impl HttpConfig {
pub fn from_map(config_map: HashMap<&str, String>) -> Self {
let mut config = HttpConfig { connect_timeout: None, timeout: None };
if let Some(connect_timeout) = config_map.get("connect_timeout") {
config.connect_timeout = Some(connect_timeout.parse::<u16>().unwrap());
}
if let Some(timeout) = config_map.get("timeout") {
config.timeout = Some(timeout.parse::<u16>().unwrap());
}
config
}
}
pub struct RequestWrapper {
headers: HashMap<String, String>,
request: RequestBuilder,
}
pub struct ResponseWrapper {
response: Response,
}
impl RequestWrapper {
pub fn build_default(url: &str, method: &str) -> RequestWrapper {
let request = Client::new().request(
Method::from_str(method.to_uppercase().as_str()).unwrap(),
Url::from_str(url).unwrap(),
);
RequestWrapper {
headers: map!(
"user-agent".to_string() => "Feign Http".to_string()),
request,
}
}
pub fn build_with_config(url: &str, method: &str, config: HttpConfig) -> RequestWrapper {
let mut client = Client::builder();
if let Some(millisecond) = config.connect_timeout {
client = client.connect_timeout(Duration::from_millis(millisecond as u64));
}
if let Some(millisecond) = config.timeout {
client = client.timeout(Duration::from_millis(millisecond as u64));
}
let request = client.build().unwrap().request(
Method::from_str(method.to_uppercase().as_str()).unwrap(),
Url::from_str(url).unwrap(),
);
RequestWrapper {
headers: map!(
"user-agent".to_string() => "Feign Http".to_string()),
request,
}
}
pub fn headers(mut self, header_map: HashMap<&str, String>) -> Self {
for (k, v) in header_map {
self.headers.insert(k.to_string().to_lowercase(), v);
}
self
}
fn set_header(mut self) -> Self {
let mut request = self.request;
for (k, v) in &self.headers {
request = request.header(k.as_str(), v);
}
self.request = request;
self
}
pub fn query(mut self, query: &Vec<(&str, String)>) -> Self {
let mut request = self.request;
request = request.query(query.as_slice());
self.request = request;
self
}
pub async fn send(self) -> Result<ResponseWrapper> {
let mut response = self.set_header().request.send().await?;
response = response.error_for_status()?;
Ok(ResponseWrapper { response })
}
pub async fn send_text(
mut self,
text: String,
) -> Result<ResponseWrapper> {
self.request = self.request.body(Body::from(text));
self.send().await
}
pub async fn send_json<T>(
mut self,
json: &T,
) -> Result<ResponseWrapper>
where
T: serde::ser::Serialize,
{
self.request = self.request.json(json);
self.send().await
}
}
impl ResponseWrapper {
pub fn status(self) -> http::StatusCode {
self.response.status()
}
pub async fn text(self) -> Result<String> {
Ok(self.response.text().await?)
}
pub async fn json<T>(self) -> Result<T>
where
T: serde::de::DeserializeOwned,
{
Ok(self.response.json::<T>().await?)
}
}