Skip to main content

HttpTransport

Trait HttpTransport 

Source
pub trait HttpTransport: Debug {
    // Required methods
    fn get<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        path: &'life1 str,
        headers: &'life2 [(String, String)],
        timeout: Option<Duration>,
    ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             Self: 'async_trait;
    fn post<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        path: &'life1 str,
        body: &'life2 str,
        headers: &'life3 [(String, String)],
        timeout: Option<Duration>,
    ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait,
             Self: 'async_trait;
    fn put<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        path: &'life1 str,
        body: &'life2 str,
        headers: &'life3 [(String, String)],
        timeout: Option<Duration>,
    ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait,
             Self: 'async_trait;
    fn delete<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        path: &'life1 str,
        body: &'life2 str,
        headers: &'life3 [(String, String)],
        timeout: Option<Duration>,
    ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
       where 'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait,
             Self: 'async_trait;
}
Expand description

Production HTTP transport seam and its typed surfaces.

HttpTransport is the async injection point downstream clients consume; TransportResponse is its success envelope (2xx status, redacted headers, body); TransportError is its typed failure surface, and TransportErrorClass is the label telemetry and retry layers use to partition REST-transport failures without parsing error messages. The native default implementation is ReqwestTransport; the browser default lives in cow-sdk-core (transport::fetch). Production injection point for HTTPS REST transport.

Implementations dispatch REST requests without committing the calling crate to any specific backend. The native default implementation is ReqwestTransport; the browser default implementation is FetchTransport, the wasm32 sibling in this crate’s transport::fetch module, which bridges the same async signature through JsFuture.

Most consumers never implement this trait. The orderbook and subgraph builders install the per-target default automatically, so the zero-config .build() path serves native and browser callers alike. Common tuning does not require a custom transport either: reuse a pre-configured reqwest::Client (proxy, custom TLS, connection pool) through the native builder’s .client(..) seam, supply credentials through .api_key(..) and the per-call header set, and shape retry, rate limiting, timeout, and user-agent through TransportPolicy. Implementing this trait is the deliberate escape hatch for three cases: a JavaScript host supplying its own fetch or callback (see cow_sdk_js::exports::JsCallbackHttpTransport), test doubles that record or replay requests, and wrapping an inner transport to add caching or other middleware. The Arc<dyn HttpTransport> seam is what keeps those injectable at runtime.

This trait does not retry. Retry, jitter, rate limiting, and Retry-After handling are applied at the orderbook layer via cow_sdk_core::transport::policy::TransportPolicy. See docs/guides/transport.md.

Every method carries the per-call header set and an optional per-call timeout alongside the URL and body so downstream crates compose typed clients without holding a parallel reqwest::Client for header or deadline overrides. Implementations merge per-call headers with any constructor-configured defaults, honor the per-call timeout when Some, and map non-2xx responses into TransportError::HttpStatus so the calling layer receives the numeric status, response headers, and raw body through the typed error channel. The success channel carries the same fidelity: Ok returns a TransportResponse with the 2xx status code, the response headers, and the body, so calling layers never have to fabricate response metadata.

The trait uses async_trait so downstream clients can hold the transport behind Arc<dyn HttpTransport + Send + Sync> without reaching for a bespoke adapter trait. Implementations carry std::fmt::Debug so trait objects render in derived Debug output of consumer-facing clients without bespoke formatters. On native targets the returned futures are Send so downstream crates compose them onto multi-threaded runtimes; on wasm32 targets the futures drop the Send bound so the browser adapter remains viable.

§Implementing

The transport is held behind Arc<dyn HttpTransport>, so an implementor annotates the impl with the re-exported async_trait. cow-sdk-core re-exports the macro, so an out-of-tree implementor does not declare an async-trait dependency itself:

use std::time::Duration;
use cow_sdk_core::{async_trait, HttpTransport, TransportError, TransportResponse};

#[derive(Debug)]
struct MyTransport;

#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
impl HttpTransport for MyTransport {
    async fn get(
        &self,
        path: &str,
        headers: &[(String, String)],
        timeout: Option<Duration>,
    ) -> Result<TransportResponse, TransportError> {
        todo!("dispatch the GET through your HTTP backend")
    }
    async fn post(
        &self,
        path: &str,
        body: &str,
        headers: &[(String, String)],
        timeout: Option<Duration>,
    ) -> Result<TransportResponse, TransportError> {
        todo!()
    }
    async fn put(
        &self,
        path: &str,
        body: &str,
        headers: &[(String, String)],
        timeout: Option<Duration>,
    ) -> Result<TransportResponse, TransportError> {
        todo!()
    }
    async fn delete(
        &self,
        path: &str,
        body: &str,
        headers: &[(String, String)],
        timeout: Option<Duration>,
    ) -> Result<TransportResponse, TransportError> {
        todo!()
    }
}

Required Methods§

Source

fn get<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, path: &'life1 str, headers: &'life2 [(String, String)], timeout: Option<Duration>, ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Performs an HTTP GET against the supplied path.

Implementations merge headers with any constructor-configured defaults and apply timeout when Some, otherwise honor the transport’s default timeout. The semantics of path are adapter-defined: the native ReqwestTransport resolves it against the configured base URL, while other adapters may interpret it as an absolute URL.

§Errors

Returns TransportError::Transport when the underlying backend fails, with TransportError::class set to the categorical failure mode. Returns TransportError::Configuration when the adapter could not build the request from the supplied input. Returns TransportError::HttpStatus when the remote endpoint responded with a non-2xx status code.

Source

fn post<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, path: &'life1 str, body: &'life2 str, headers: &'life3 [(String, String)], timeout: Option<Duration>, ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Performs an HTTP POST with a JSON-compatible body.

§Errors

Returns TransportError::Transport when the underlying backend fails, with TransportError::class set to the categorical failure mode. Returns TransportError::Configuration when the adapter could not build the request from the supplied input. Returns TransportError::HttpStatus when the remote endpoint responded with a non-2xx status code.

Source

fn put<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, path: &'life1 str, body: &'life2 str, headers: &'life3 [(String, String)], timeout: Option<Duration>, ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Performs an HTTP PUT with a JSON-compatible body.

§Errors

Returns TransportError::Transport when the underlying backend fails, with TransportError::class set to the categorical failure mode. Returns TransportError::Configuration when the adapter could not build the request from the supplied input. Returns TransportError::HttpStatus when the remote endpoint responded with a non-2xx status code.

Source

fn delete<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, path: &'life1 str, body: &'life2 str, headers: &'life3 [(String, String)], timeout: Option<Duration>, ) -> Pin<Box<dyn Future<Output = Result<TransportResponse, TransportError>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Performs an HTTP DELETE with a JSON-compatible body.

§Errors

Returns TransportError::Transport when the underlying backend fails, with TransportError::class set to the categorical failure mode. Returns TransportError::Configuration when the adapter could not build the request from the supplied input. Returns TransportError::HttpStatus when the remote endpoint responded with a non-2xx status code.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§