use std::collections::HashMap;
use std::str::FromStr;
use reqwest::RequestBuilder;
use serde::de::DeserializeOwned;
use url::Url;
use crate::errors::response_error::RequestError;
use crate::utils::credentials_manager::CredentialsManager;
pub(crate) async fn fetch_endpoint<D: DeserializeOwned>(
credentials_manager: &CredentialsManager,
http_client: &reqwest::Client,
uri: Url,
method: &str,
body: &str,
headers: &HashMap<String, String>,
) -> Result<D, RequestError> {
let raw_result =
fetch_endpoint_raw(credentials_manager, http_client, uri, method, body, headers).await?;
raw_result.json().await.map_err(RequestError::from)
}
async fn fetch_endpoint_raw(
credentials_manager: &CredentialsManager,
http_client: &reqwest::Client,
uri: Url,
method: &str,
body: &str,
headers: &HashMap<String, String>,
) -> Result<reqwest::Response, RequestError> {
let auth_headers = credentials_manager.get_auth_headers();
let headers = headers
.iter()
.chain(auth_headers.iter())
.map(|(key, value)| (key.clone(), value.clone()))
.collect::<HashMap<String, String>>();
let request = build_request(uri, http_client, method, body, &headers)?;
let response = request.send().await.map_err(RequestError::from)?;
let status = response.status();
if !status.is_success() {
return Err(RequestError::from((status.as_u16(), body.to_string())));
}
Ok(response)
}
fn build_request(
uri: Url,
http_client: &reqwest::Client,
method: &str,
body: &str,
headers: &HashMap<String, String>,
) -> Result<RequestBuilder, RequestError> {
let method =
reqwest::Method::from_str(method).map_err(|e| RequestError::from(e.to_string()))?;
Ok(http_client
.request(method, uri)
.body(body.to_string())
.headers(
headers
.iter()
.map(|(key, value)| {
(
reqwest::header::HeaderName::from_str(key)
.map_err(|e| RequestError::from(e.to_string())),
reqwest::header::HeaderValue::from_str(value)
.map_err(|e| RequestError::from(e.to_string())),
)
})
.filter_map(|(key, value)| match (key, value) {
(Ok(key), Ok(value)) => Some((key, value)),
_ => None,
})
.collect(),
))
}