Skip to main content

ClientHandler

Trait ClientHandler 

Source
pub trait ClientHandler:
    Send
    + Sync
    + 'static {
    // Provided methods
    fn run(&self, conn: &mut Conn) -> impl Future<Output = Result<()>> + Send { ... }
    fn after_response(
        &self,
        conn: &mut Conn,
    ) -> impl Future<Output = Result<()>> + Send { ... }
    fn name(&self) -> Cow<'static, str> { ... }
}
Expand description

Client middleware extension point.

ClientHandler is the composition primitive for trillium-client middleware. It mirrors the server-side trillium::Handler in spirit — handlers compose into tuples, halting on the conn short-circuits the chain — but differs in shape because the client has different ownership semantics: the conn is user-owned, so handlers take &mut Conn rather than owned Conn, and they return Result<()> because client execution can fail outright (TLS handshake, refresh token, signing, etc.).

§Lifecycle

Each Conn::exec call runs handlers in two passes:

  1. Forward pass — run. Each handler runs in declared order. A handler may mutate the request, short-circuit by calling Conn::halt + populating synthetic response state (cache hit, mocked response), or fail. If any handler halts, subsequent run methods are skipped.
  2. Network round-trip. Skipped if the conn is halted.
  3. Reverse pass — after_response. Each handler’s after_response runs in reverse order, regardless of halt status. This mirrors trillium::Handler::before_send and lets handlers that observe the response (loggers, metrics, status checkers) record cache hits and short-circuited responses, not just transport-backed ones.

§Re-execution

Handlers that need to re-issue a request (follow-redirects, retry, auth-refresh) construct a fresh Conn from a Client they own — typically a separate one without recursion into the same handler chain — execute it, and std::mem::swap it with the user’s conn. See the follow_redirects and retry handlers for examples.

Pre-executing the same conn from inside run is undefined: the conn is mid-pipeline at that point and re-entering IntoFuture recurses through the same handler chain. Don’t.

§Type erasure

Implementors write ClientHandler using native async fn syntax. The crate type-erases handlers internally for storage on Client; Client::with_handler accepts any impl ClientHandler, and Client::downcast_handler is the way to recover the concrete type from a Client that has one installed.

Provided Methods§

Source

fn run(&self, conn: &mut Conn) -> impl Future<Output = Result<()>> + Send

Forward-pass hook, called before the network round-trip in declared order.

A handler can mutate the request, halt to short-circuit, or fail. The default implementation is a no-op.

Source

fn after_response( &self, conn: &mut Conn, ) -> impl Future<Output = Result<()>> + Send

Reverse-pass hook, called after the network round-trip (or after a halt-skipped network call) in reverse declared order. Always runs regardless of halt status or transport error.

A handler can observe the response, mutate it before passing it to upstream handlers, recover from a transport-level error, or fail.

Transport errors. If the network call failed (connect refused, TLS handshake error, malformed HTTP frame, timeout), the framework stashes the error on Conn::error and runs after_response anyway. A handler that recovers (stale-if-error cache, retry-with-fallback, circuit breaker) should:

  1. Inspect conn.error() to detect the failure.
  2. Populate response state synthetically (set_status, response_headers_mut, set_response_body).
  3. Call conn.take_error() to clear the error so the awaited conn returns Ok.

If no handler clears the error, it propagates as Err from the awaited conn.

The default implementation is a no-op.

Source

fn name(&self) -> Cow<'static, str>

Human-readable name for logging/debugging. Defaults to the type name.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementations on Foreign Types§

Source§

impl ClientHandler for ()

Source§

impl<A: ClientHandler> ClientHandler for (A,)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler> ClientHandler for (A, B)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler> ClientHandler for (A, B, C)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler> ClientHandler for (A, B, C, D)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler> ClientHandler for (A, B, C, D, E)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler> ClientHandler for (A, B, C, D, E, F)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler> ClientHandler for (A, B, C, D, E, F, G)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler, J: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I, J)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler, J: ClientHandler, K: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I, J, K)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler, J: ClientHandler, K: ClientHandler, L: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I, J, K, L)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler, J: ClientHandler, K: ClientHandler, L: ClientHandler, M: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I, J, K, L, M)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler, J: ClientHandler, K: ClientHandler, L: ClientHandler, M: ClientHandler, N: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I, J, K, L, M, N)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<A: ClientHandler, B: ClientHandler, C: ClientHandler, D: ClientHandler, E: ClientHandler, F: ClientHandler, G: ClientHandler, H: ClientHandler, I: ClientHandler, J: ClientHandler, K: ClientHandler, L: ClientHandler, M: ClientHandler, N: ClientHandler, O: ClientHandler> ClientHandler for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Source§

impl<H: ClientHandler> ClientHandler for Option<H>

Source§

async fn run(&self, conn: &mut Conn) -> Result<()>

Source§

async fn after_response(&self, conn: &mut Conn) -> Result<()>

Source§

fn name(&self) -> Cow<'static, str>

Implementors§