Skip to main content

HttpClient

Struct HttpClient 

Source
pub struct HttpClient {
    pub base_url: Url,
    /* private fields */
}
Expand description

Shared HTTP client with base URL, throttle, retry policy and retry config.

This is the common structure used by all API clients to hold the transport every attempt is sent on, the base URL, and the hooks its send loop, send, runs on every request.

Fields§

§base_url: Url

Base URL for API requests

Implementations§

Source§

impl HttpClient

Source

pub fn with_base_url(&self, base_url: &str) -> Result<Self, ApiError>

Clone this client, pointed at a different base URL.

The transport (and so its connection pool), throttle (and so its hold), retry policy, retry config, runtime, and concurrency limiter are all shared with the original. Use this to reach a sibling API host that should share the same transport configuration and request budget — a venue whose APIs live on their own subdomains is consumed by one client, and a 429 on one holds them all.

Sharing the concurrency limiter is deliberate: the limit exists to keep Cloudflare from seeing a burst from this process, and that is a per-process concern rather than a per-host one.

§Path prefixes are ignored

Request paths are absolute (/user-pnl), and resolving an absolute path against a base replaces the base’s path entirely. So a prefix in base_url is silently dropped, with or without a trailing slash:

http://host          + /user-pnl -> http://host/user-pnl
http://host/proxy    + /user-pnl -> http://host/user-pnl   (prefix gone)
http://host/proxy/   + /user-pnl -> http://host/user-pnl   (prefix gone)

Point this at a scheme, host, and port — not at a sub-path. Fronting the API with a path-prefixed reverse proxy is not supported.

Source

pub fn runtime(&self) -> &Arc<dyn Runtime> ⓘ

The runtime this client’s waits, clock reads and spawns go through: the one its builder was given, else the target’s default. Shared with every with_base_url sibling.

Source

pub async fn acquire_concurrency(&self) -> Option<OwnedSemaphorePermit>

Acquire a concurrency permit, if a limiter is configured.

The returned permit must be held until the HTTP response has been received. Dropping the permit releases the concurrency slot. Returns None when no concurrency limit is set.

send takes one for each attempt. Transitional for any other caller: no crate calls it since Stories 3.4 to 3.6 moved the hand-written loops onto send, but tests observe the permit through it. It is removed from the public API once they can observe it another way, and docs/s1-removals.md names send.

Source

pub async fn get_bytes( &self, path: &str, query: &[(String, String)], ) -> Result<Vec<u8>, ApiError>

GET a URL and return the raw response body as bytes.

Use this for endpoints that return non-JSON payloads (e.g. application/zip downloads). It runs on send, so it is throttled, gated, retried and held as every other request is.

A non-2xx response is ApiError::Response.

§Errors

Returns ApiError on URL-join failure, network errors, or non-2xx responses.

Source§

impl HttpClient

Source

pub async fn health<E: RequestError>( &self, path: &str, costs: &[Cost], ) -> Result<Pong, E>

Ping path with one GET on send, charging costs.

The ping takes a concurrency permit and the throttle, and is retried and held by the client’s policy, as every other request is. Its Pong::round_trip is that of the attempt that answered, so every venue’s ping latency means the same thing.

§Errors

A final non-2xx response is ApiError::Response as E, and so is a failure before one (a refused cost, a transport error).

Source§

impl HttpClient

Source

pub async fn send( &self, parts: RequestParts, costs: &[Cost], auth: Option<&DynAuthenticator<'_>>, ) -> Result<Response, ApiError>

Send parts, retrying as the client’s policy decides.

Each attempt takes a concurrency permit, waits while the throttle charges it (Throttle::acquire, with costs), is signed by auth when one is given, and is sent, within parts.timeout when it is set. The throttle then sees the response (Throttle::observe), the policy decides what follows (RetryPolicy::decide), and a hold the decision carries is applied (Throttle::hold) whether or not the request is retried.

A retry releases the permit and sleeps the longer of the policy’s wait and the loop’s own floor, RetryConfig::retry_delay for the attempt. The floor belongs to the loop, so no policy can retry sooner. The loop never retries past RetryConfig::max_retries, whatever the policy says.

Each retry logs a WARN under the polyoxide_core target, Retriable status <code> on <path>, retry <n> after <ms>ms, where <ms> is the longer of the retry’s sleep and the hold its decision set, since the retry waits out both. A hold that is not a retry logs one too: Status <code> on <path>, not retried: every request held <ms>ms.

Returns the response the policy is done with, whatever its status; one it fails, or would retry with no retry left, is an error.

§Errors

Trait Implementations§

Source§

impl Clone for HttpClient

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for HttpClient

Written by hand: the throttle and the policy are trait objects, which print nothing useful.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more