use crate::{
DEFAULT_BASE_URL, error::GleifError, error::Result, request_builder::GleifRequestBuilder,
};
use reqwest::{Client as ReqwestClient, Method};
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use std::sync::Arc;
use url::Url;
#[derive(Clone, Debug)]
pub struct GleifClient {
client: Arc<ClientWithMiddleware>,
base_url: Url,
}
impl Default for GleifClient {
fn default() -> Self {
GleifClientBuilder::new().build().unwrap()
}
}
impl GleifClient {
#[must_use]
pub fn new() -> Self {
Self::builder()
.build()
.expect("Default config should not fail")
}
#[must_use]
pub fn builder() -> GleifClientBuilder {
GleifClientBuilder::new()
}
#[must_use]
pub fn from_middleware_client(client: ClientWithMiddleware) -> Self {
Self {
client: Arc::new(client),
base_url: Url::parse(DEFAULT_BASE_URL).expect("Default base URL should be valid"),
}
}
#[must_use]
pub fn from_reqwest_client(client: ReqwestClient) -> Self {
let middleware = ClientBuilder::new(client).build();
Self::from_middleware_client(middleware)
}
#[must_use]
pub fn base_url(&self) -> &Url {
&self.base_url
}
#[must_use]
pub fn client(&self) -> &Arc<ClientWithMiddleware> {
&self.client
}
pub(crate) fn request(&self, path: &str) -> GleifRequestBuilder {
GleifRequestBuilder::new(self.clone(), Method::GET, path)
}
}
pub struct GleifClientBuilder {
middleware_builder: Option<ClientBuilder>,
reqwest_client: Option<ReqwestClient>,
base_url: String,
}
impl Default for GleifClientBuilder {
fn default() -> Self {
Self {
middleware_builder: None,
reqwest_client: None,
base_url: String::from(DEFAULT_BASE_URL),
}
}
}
impl GleifClientBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn base_url(mut self, url: impl Into<String>) -> Self {
self.base_url = url.into();
self
}
#[must_use]
pub fn reqwest_client(mut self, client: ReqwestClient) -> Self {
self.reqwest_client = Some(client);
self
}
#[must_use]
pub fn middleware_builder(mut self, builder: ClientBuilder) -> Self {
self.middleware_builder = Some(builder);
self
}
pub fn build(self) -> Result<GleifClient> {
let reqwest_client = self.reqwest_client.unwrap_or_default();
let client = if let Some(builder) = self.middleware_builder {
builder.build()
} else {
ClientBuilder::new(reqwest_client).build()
};
let base_url = Url::parse(&self.base_url).map_err(GleifError::UrlParseError)?;
Ok(GleifClient {
client: Arc::new(client),
base_url,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use reqwest::Client as ReqwestClient;
use reqwest_middleware::ClientBuilder;
use reqwest_retry::{RetryTransientMiddleware, policies::ExponentialBackoff};
#[test]
fn test_client_construction_from_reqwest() {
let reqwest_client = ReqwestClient::new();
let client = GleifClient::from_reqwest_client(reqwest_client);
assert_eq!(client.base_url().as_str(), DEFAULT_BASE_URL);
}
#[test]
fn test_client_construction_from_middleware_client() {
let reqwest_client = ReqwestClient::new();
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3);
let client_with_middleware = ClientBuilder::new(reqwest_client)
.with(RetryTransientMiddleware::new_with_policy(retry_policy))
.build();
let client = GleifClient::from_middleware_client(client_with_middleware);
assert_eq!(client.base_url().as_str(), DEFAULT_BASE_URL);
}
#[test]
fn test_client_builder() {
let client = GleifClient::builder()
.build()
.expect("Client build should succeed");
assert_eq!(client.base_url().as_str(), DEFAULT_BASE_URL);
let custom_url = "https://custom.gleif.org/api/v2";
let client = GleifClient::builder()
.base_url(custom_url)
.build()
.expect("Client build should succeed");
assert_eq!(client.base_url().as_str(), custom_url);
}
#[test]
fn test_client_new() {
let client = GleifClient::new();
assert_eq!(client.base_url().as_str(), DEFAULT_BASE_URL);
}
#[test]
fn test_client_builder_with_middleware() {
let reqwest_client = ReqwestClient::new();
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3);
let middleware_builder = ClientBuilder::new(reqwest_client.clone())
.with(RetryTransientMiddleware::new_with_policy(retry_policy));
let client = GleifClient::builder()
.middleware_builder(middleware_builder)
.build()
.expect("Client build should succeed");
assert_eq!(client.base_url().as_str(), DEFAULT_BASE_URL);
}
}