Middleware

Trait Middleware 

Source
pub trait Middleware: Send + Sync {
    // Required method
    fn handle(
        &mut self,
        request: &mut Request,
        next: impl Endpoint,
    ) -> impl Future<Output = Result<Response>> + Send + Sync;
}
Expand description

Trait for implementing middleware that can process HTTP requests and responses.

Middleware sits between the initial request and the final endpoint, allowing you to implement cross-cutting concerns like authentication, logging, rate limiting, compression, and other request/response transformations.

Middleware operates in a chain where each middleware can:

  • Inspect and modify the incoming request
  • Decide whether to call the next middleware/endpoint in the chain
  • Inspect and modify the outgoing response
  • Handle errors and implement fallback behavior

§Implementation Pattern

A typical middleware implementation follows this pattern:

  1. Pre-process the request (logging, validation, etc.)
  2. Call next.respond(request).await to continue the chain
  3. Post-process the response (add headers, transform body, etc.)
  4. Return the final response

§Examples

§Request Logging Middleware

use http_kit::{Request, Response, Result, Middleware, Endpoint};

struct LoggingMiddleware;

impl Middleware for LoggingMiddleware {
    async fn handle(&self, request: &mut Request, next: impl Endpoint) -> Result<Response> {
        println!("Incoming: {} {}", request.method(), request.uri());

        let response = next.respond(request).await?;

        println!("Outgoing: {}", response.status());
        Ok(response)
    }
}

§Authentication Middleware

use http_kit::{Request, Response, Result, Middleware, Endpoint, StatusCode};

struct AuthMiddleware {
    required_token: String,
}

impl Middleware for AuthMiddleware {
    async fn handle(&self, request: &mut Request, next: impl Endpoint) -> Result<Response> {
        if let Some(auth_header) = request.get_header(http::header::AUTHORIZATION) {
            if auth_header.as_bytes() == self.required_token.as_bytes() {
                return next.respond(request).await;
            }
        }

        Ok(Response::new(StatusCode::UNAUTHORIZED, "Authentication required"))
    }
}

§Response Header Middleware

use http_kit::{Request, Response, Result, Middleware, Endpoint};

struct HeaderMiddleware;

impl Middleware for HeaderMiddleware {
    async fn handle(&self, request: &mut Request, next: impl Endpoint) -> Result<Response> {
        let mut response = next.respond(request).await?;

        response.insert_header(
            http::header::SERVER,
            http::HeaderValue::from_static("http-kit/1.0")
        );

        Ok(response)
    }
}

Required Methods§

Source

fn handle( &mut self, request: &mut Request, next: impl Endpoint, ) -> impl Future<Output = Result<Response>> + Send + Sync

Processes a request through the middleware chain.

This method receives the current request and a next parameter representing the next step in the processing chain (either another middleware or the final endpoint). The middleware can:

  • Modify the request before passing it to next
  • Decide whether to call next at all (for auth, rate limiting, etc.)
  • Transform the response returned by next
  • Handle errors and provide fallback responses
§Arguments
  • request - Mutable reference to the HTTP request being processed
  • next - The next step in the processing chain (middleware or endpoint)
§Returns

Returns a Result<Response> which can either be:

  • Ok(response) - A successful HTTP response
  • Err(error) - An error with an associated HTTP status code
§Examples
use http_kit::{Request, Response, Result, Middleware, Endpoint};

struct TimingMiddleware;

impl Middleware for TimingMiddleware {
    async fn handle(&self, request: &mut Request, next: impl Endpoint) -> Result<Response> {
        let start = std::time::Instant::now();

        // Call the next middleware or endpoint
        let response = next.respond(request).await?;

        let duration = start.elapsed();
        println!("Request processed in {:?}", duration);

        Ok(response)
    }
}

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 Middleware for ()

No-op middleware implementation for the unit type.

This implementation allows () to be used as a middleware that does nothing but pass the request through to the next handler. This is useful for:

  • Default values in generic contexts
  • Conditional middleware application
  • Testing scenarios where middleware is optional
Source§

async fn handle( &mut self, request: &mut Request, next: impl Endpoint, ) -> Result<Response>

Source§

impl<M: Middleware> Middleware for &mut M

Source§

async fn handle( &mut self, request: &mut Request, next: impl Endpoint, ) -> Result<Response>

Source§

impl<M: Middleware> Middleware for Box<M>

Source§

async fn handle( &mut self, request: &mut Request, next: impl Endpoint, ) -> Result<Response>

Source§

impl<T1: Middleware, T2: Middleware> Middleware for (T1, T2)

Middleware implementation for tuples of two middleware types.

This allows you to combine two middleware into a single unit where the first middleware wraps the second middleware, which in turn wraps the endpoint. The execution order is: self.0self.1 → endpoint.

§Examples

use http_kit::{Request, Response, Result, Middleware, Endpoint};

struct LoggingMiddleware;
impl Middleware for LoggingMiddleware {
    async fn handle(&self, request: &mut Request, next: impl Endpoint) -> Result<Response> {
        println!("Before request");
        let response = next.respond(request).await;
        println!("After request");
        response
    }
}

struct TimingMiddleware;
impl Middleware for TimingMiddleware {
    async fn handle(&self, request: &mut Request, next: impl Endpoint) -> Result<Response> {
        let start = std::time::Instant::now();
        let response = next.respond(request).await;
        println!("Elapsed: {:?}", start.elapsed());
        response
    }
}

// Combine middleware using tuple syntax
let combined = (LoggingMiddleware, TimingMiddleware);
// Execution order: LoggingMiddleware → TimingMiddleware → endpoint
Source§

async fn handle( &mut self, request: &mut Request, next: impl Endpoint, ) -> Result<Response>

Implementors§