Skip to content

Commit

Permalink
feat(api-client-framework)!: configuration and endpoint updates (#1174)
Browse files Browse the repository at this point in the history
* feat!(api-client-framework): re-export reqwest related crates

* feat(api-client-framework): make explicit use of reqwest-middlewares for client config; add headers setup into Endpoint trait
  • Loading branch information
rimrakhimov authored Jan 22, 2025
1 parent c99d6a7 commit c55b2bb
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 11 deletions.
1 change: 0 additions & 1 deletion libs/api-client-framework/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ edition = "2021"
anyhow = { version = "1.0", default-features = false }
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls"] }
reqwest-middleware = { version = "0.4", default-features = false }
reqwest-retry = { version = "0.7", default-features = false }
serde = { version = "1", default-features = false }
serde_json = { version = "1", default-features = false, features = ["std"] }
serde_path_to_error = { version = "0.1.16", default-features = false }
Expand Down
25 changes: 15 additions & 10 deletions libs/api-client-framework/src/async_client.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
use super::endpoint::Endpoint;
use crate::Error;
use reqwest::{header::HeaderMap, Response, StatusCode};
use reqwest_middleware::ClientBuilder;
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
use reqwest_middleware::{ClientBuilder, Middleware};
use serde::Deserialize;
use std::time::Duration;
use std::{sync::Arc, time::Duration};

#[derive(Clone)]
pub struct HttpApiClientConfig {
/// The maximum time limit for an API request. If a request takes longer than this, it will be
/// cancelled.
pub http_timeout: Duration,
/// Maximum number of allowed retries attempts. Defaults to 1.
pub max_retries: u32,
/// A default set of HTTP headers which will be sent with each API request.
pub default_headers: HeaderMap,
/// Middlewares that will process each API request before the request is actually sent.
pub middlewares: Vec<Arc<dyn Middleware>>,
}

impl Default for HttpApiClientConfig {
fn default() -> Self {
Self {
http_timeout: Duration::from_secs(30),
max_retries: 1,
default_headers: HeaderMap::default(),
middlewares: Vec::new(),
}
}
}
Expand All @@ -35,14 +34,16 @@ pub struct HttpApiClient {

impl HttpApiClient {
pub fn new(base_url: url::Url, config: HttpApiClientConfig) -> Result<Self, Error> {
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(config.max_retries);
let reqwest_client = reqwest::Client::builder()
.default_headers(config.default_headers)
.timeout(config.http_timeout)
.build()?;
let client = ClientBuilder::new(reqwest_client)
.with(RetryTransientMiddleware::new_with_policy(retry_policy))
.build();
let mut client_builder = ClientBuilder::new(reqwest_client);
for middleware in config.middlewares {
client_builder = client_builder.with_arc(middleware);
}
let client = client_builder.build();

Ok(Self {
base_url,
http_client: client,
Expand All @@ -67,6 +68,10 @@ impl HttpApiClient {
);
}

if let Some(headers) = endpoint.headers() {
request = request.headers(headers);
}

let response = request.send().await?;
process_api_response(response).await
}
Expand Down
8 changes: 8 additions & 0 deletions libs/api-client-framework/src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ pub trait Endpoint {
None
}

/// The set of headers to be sent with request. Defaults to `None`.
///
/// Implementors should inline this.
#[inline]
fn headers(&self) -> Option<reqwest::header::HeaderMap> {
None
}

/// The HTTP body associated with this endpoint. If not implemented, defaults to `None`.
///
/// Implementors should inline this.
Expand Down
4 changes: 4 additions & 0 deletions libs/api-client-framework/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ mod endpoint;
pub use async_client::{HttpApiClient, HttpApiClientConfig};
pub use endpoint::{serialize_query, Endpoint};

pub use reqwest;
pub use reqwest_middleware;
pub use url;

/******************** Config definition ********************/

#[derive(Debug, thiserror::Error)]
Expand Down

0 comments on commit c55b2bb

Please sign in to comment.