Skip to main content

Middleware

Trait Middleware 

Source
pub trait Middleware: Send {
    type Error: HttpError;

    // Required method
    fn handle<E: Endpoint>(
        &mut self,
        request: &mut Request,
        next: E,
    ) -> impl Future<Output = Result<Response, MiddlewareError<E::Error, Self::Error>>> + Send;
}
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, Body, BoxHttpError};
use http_kit::middleware::MiddlewareError;

struct LoggingMiddleware;

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

        let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;

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

§Authentication Middleware

use http_kit::{Request, Response, Result, Middleware, Endpoint, StatusCode, Body, BoxHttpError};
use http_kit::middleware::MiddlewareError;

struct AuthMiddleware {
    required_token: String,
}

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

        Ok(Response::new(Body::from_bytes("Authentication required")))
    }
}

§Response Header Middleware

use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
use http_kit::middleware::MiddlewareError;

struct HeaderMiddleware;

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

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

        Ok(response)
    }
}

Required Associated Types§

Source

type Error: HttpError

The error type that this middleware can produce.

Required Methods§

Source

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

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, Body, BoxHttpError};
use http_kit::middleware::MiddlewareError;

struct TimingMiddleware;

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

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

        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".

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§

type Error = Infallible

Source§

async fn handle<E: Endpoint>( &mut self, request: &mut Request, next: E, ) -> Result<Response, MiddlewareError<E::Error, Self::Error>>

Source§

impl<M: Middleware> Middleware for &mut M

Source§

type Error = <M as Middleware>::Error

Source§

async fn handle<E: Endpoint>( &mut self, request: &mut Request, next: E, ) -> Result<Response, MiddlewareError<E::Error, Self::Error>>

Source§

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

Source§

type Error = <M as Middleware>::Error

Source§

async fn handle<E: Endpoint>( &mut self, request: &mut Request, next: E, ) -> Result<Response, MiddlewareError<E::Error, Self::Error>>

Implementors§