113 lines
3.6 KiB
Rust
113 lines
3.6 KiB
Rust
use crate::endpoints::{Endpoint, ErrorKind, ResponseError};
|
|
use crate::Client;
|
|
use http::header::{CONTENT_TYPE, USER_AGENT};
|
|
use http::{HeaderMap, HeaderValue, Method, StatusCode};
|
|
use serde::de::DeserializeOwned;
|
|
use serde::Serialize;
|
|
|
|
pub struct ReqwestClient {
|
|
client: reqwest::Client,
|
|
base_url: String,
|
|
}
|
|
|
|
impl ReqwestClient {
|
|
pub fn new(base_url: &str, application: &str) -> Self {
|
|
let mut headers = HeaderMap::new();
|
|
headers.insert(
|
|
CONTENT_TYPE,
|
|
HeaderValue::from_str("application/json").unwrap(),
|
|
);
|
|
headers.insert(USER_AGENT, HeaderValue::from_str(application).unwrap());
|
|
|
|
let client_builder = reqwest::ClientBuilder::new().default_headers(headers);
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
let client_builder = { client_builder.https_only(true) };
|
|
|
|
let client = client_builder.build().unwrap();
|
|
|
|
ReqwestClient {
|
|
client,
|
|
base_url: base_url.to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait::async_trait(?Send)]
|
|
impl Client for ReqwestClient {
|
|
fn base_url(&self) -> &str {
|
|
&self.base_url
|
|
}
|
|
|
|
async fn call<'a, I, O, E>(
|
|
&self,
|
|
endpoint: &E,
|
|
data: &I,
|
|
path_params: &impl AsRef<[(&'a str, &'a str)]>,
|
|
) -> Result<O, ResponseError>
|
|
where
|
|
I: Serialize + DeserializeOwned + Send + 'static,
|
|
O: Serialize + DeserializeOwned + Send + 'static,
|
|
E: Endpoint<Request = I, Response = O> + Send + 'static,
|
|
{
|
|
let url = endpoint.template_path(self.base_url(), path_params);
|
|
|
|
let req = self.client.request(E::METHOD, &url);
|
|
|
|
let req = if E::METHOD == Method::GET {
|
|
req.query(&data)
|
|
} else {
|
|
req.json(&data)
|
|
};
|
|
|
|
let response = req.send().await.map_err(|e| ResponseError {
|
|
kind: ErrorKind::Other,
|
|
code: "ReqwestClient:Fail".to_string(),
|
|
message: e.to_string(),
|
|
status: None,
|
|
})?;
|
|
|
|
let status = response.status();
|
|
if status.is_client_error() || status.is_server_error() {
|
|
match response.json::<ResponseError>().await {
|
|
Ok(res) => Err(res),
|
|
Err(e) => Err(ResponseError {
|
|
kind: ErrorKind::ApiError,
|
|
code: "ReqwestClient:ApiGenericError".to_string(),
|
|
message: e.to_string(),
|
|
status: Some(status.as_u16()),
|
|
}),
|
|
}
|
|
} else if status.is_success() {
|
|
if status == StatusCode::NO_CONTENT.as_u16() {
|
|
return if let Some(val) = E::default_response() {
|
|
Ok(val)
|
|
} else {
|
|
Err(ResponseError {
|
|
kind: ErrorKind::ApiError,
|
|
code: "ReqwestClient:ResponseError204".to_string(),
|
|
message: "Response is empty".to_string(),
|
|
status: Some(status.as_u16()),
|
|
})
|
|
};
|
|
}
|
|
|
|
let data = response.json::<O>().await.map_err(|e| ResponseError {
|
|
kind: ErrorKind::ApiError,
|
|
code: "ReqwestClient:JsonError".to_string(),
|
|
message: e.to_string(),
|
|
status: Some(status.as_u16()),
|
|
})?;
|
|
|
|
Ok(data)
|
|
} else {
|
|
Err(ResponseError {
|
|
kind: ErrorKind::ApiError,
|
|
code: "ReqwestClient:ApiUnknownStatusError".to_string(),
|
|
message: status.to_string(),
|
|
status: Some(status.as_u16()),
|
|
})
|
|
}
|
|
}
|
|
}
|