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:
- Pre-process the request (logging, validation, etc.)
- Call
next.respond(request).awaitto continue the chain - Post-process the response (add headers, transform body, etc.)
- 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§
Required Methods§
Sourcefn handle<E: Endpoint>(
&mut self,
request: &mut Request,
next: E,
) -> impl Future<Output = Result<Response, MiddlewareError<E::Error, Self::Error>>> + Send
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
nextat 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 processednext- The next step in the processing chain (middleware or endpoint)
§Returns
Returns a Result<Response> which can either be:
Ok(response)- A successful HTTP responseErr(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.
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