http_kit/middleware.rs
1//! Middleware functionality for HTTP request and response processing.
2//!
3//! This module provides the core infrastructure for implementing middleware in the HTTP processing
4//! pipeline. Middleware allows you to modify or inspect HTTP requests and responses during processing,
5//! enabling functionality like:
6//!
7//! - Request/response logging
8//! - Authentication and authorization
9//! - Request timeouts
10//! - Response compression
11//! - Custom headers
12//! - Request/response transformation
13//!
14//! # Usage
15//!
16//! Implement the [`Middleware`] trait to create custom middleware:
17//!
18//! ```rust
19//! use http_kit::{Request, Response, Result, Endpoint, middleware::Middleware, BoxHttpError};
20//! use http_kit::middleware::MiddlewareError;
21//!
22//! struct MyMiddleware;
23//!
24//! impl Middleware for MyMiddleware {
25//! type Error = BoxHttpError;
26//! async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
27//! // Pre-processing
28//! let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
29//! // Post-processing
30//! Ok(response)
31//! }
32//! }
33//! ```
34//!
35//! The middleware can then be composed with endpoints using [`WithMiddleware`].
36//! Multiple middleware can be chained together using tuples like `(Middleware1, Middleware2)`.
37use crate::{endpoint::EndpointImpl, error::BoxHttpError, Endpoint, HttpError, Request, Response};
38use alloc::boxed::Box;
39use core::{
40 any::type_name,
41 convert::Infallible,
42 fmt::{Debug, Display},
43 future::Future,
44 ops::DerefMut,
45 pin::Pin,
46};
47use http::StatusCode;
48/// Trait for implementing middleware that can process HTTP requests and responses.
49///
50/// Middleware sits between the initial request and the final endpoint, allowing you to
51/// implement cross-cutting concerns like authentication, logging, rate limiting, compression,
52/// and other request/response transformations.
53///
54/// Middleware operates in a chain where each middleware can:
55/// - Inspect and modify the incoming request
56/// - Decide whether to call the next middleware/endpoint in the chain
57/// - Inspect and modify the outgoing response
58/// - Handle errors and implement fallback behavior
59///
60/// # Implementation Pattern
61///
62/// A typical middleware implementation follows this pattern:
63/// 1. Pre-process the request (logging, validation, etc.)
64/// 2. Call `next.respond(request).await` to continue the chain
65/// 3. Post-process the response (add headers, transform body, etc.)
66/// 4. Return the final response
67///
68/// # Examples
69///
70/// ## Request Logging Middleware
71///
72/// ```rust
73/// use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
74/// use http_kit::middleware::MiddlewareError;
75///
76/// struct LoggingMiddleware;
77///
78/// impl Middleware for LoggingMiddleware {
79/// type Error = BoxHttpError;
80/// async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
81/// println!("Incoming: {} {}", request.method(), request.uri());
82///
83/// let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
84///
85/// println!("Outgoing: {}", response.status());
86/// Ok(response)
87/// }
88/// }
89/// ```
90///
91/// ## Authentication Middleware
92///
93/// ```rust
94/// use http_kit::{Request, Response, Result, Middleware, Endpoint, StatusCode, Body, BoxHttpError};
95/// use http_kit::middleware::MiddlewareError;
96///
97/// struct AuthMiddleware {
98/// required_token: String,
99/// }
100///
101/// impl Middleware for AuthMiddleware {
102/// type Error = BoxHttpError;
103/// async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
104/// if let Some(auth_header) = request.headers().get(http::header::AUTHORIZATION) {
105/// if auth_header.as_bytes() == self.required_token.as_bytes() {
106/// return next.respond(request).await.map_err(MiddlewareError::Endpoint);
107/// }
108/// }
109///
110/// Ok(Response::new(Body::from_bytes("Authentication required")))
111/// }
112/// }
113/// ```
114///
115/// ## Response Header Middleware
116///
117/// ```rust
118/// use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
119/// use http_kit::middleware::MiddlewareError;
120///
121/// struct HeaderMiddleware;
122///
123/// impl Middleware for HeaderMiddleware {
124/// type Error = BoxHttpError;
125/// async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
126/// let mut response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
127///
128/// response.headers_mut().insert(
129/// http::header::SERVER,
130/// http::HeaderValue::from_static("http-kit/1.0")
131/// );
132///
133/// Ok(response)
134/// }
135/// }
136/// ```
137pub trait Middleware: Send {
138 /// The error type that this middleware can produce.
139 type Error: HttpError;
140 /// Processes a request through the middleware chain.
141 ///
142 /// This method receives the current request and a `next` parameter representing
143 /// the next step in the processing chain (either another middleware or the final endpoint).
144 /// The middleware can:
145 ///
146 /// - Modify the request before passing it to `next`
147 /// - Decide whether to call `next` at all (for auth, rate limiting, etc.)
148 /// - Transform the response returned by `next`
149 /// - Handle errors and provide fallback responses
150 ///
151 /// # Arguments
152 ///
153 /// * `request` - Mutable reference to the HTTP request being processed
154 /// * `next` - The next step in the processing chain (middleware or endpoint)
155 ///
156 /// # Returns
157 ///
158 /// Returns a `Result<Response>` which can either be:
159 /// - `Ok(response)` - A successful HTTP response
160 /// - `Err(error)` - An error with an associated HTTP status code
161 ///
162 /// # Examples
163 ///
164 /// ```rust
165 /// use http_kit::{Request, Response, Result, Middleware, Endpoint, Body, BoxHttpError};
166 /// use http_kit::middleware::MiddlewareError;
167 ///
168 /// struct TimingMiddleware;
169 ///
170 /// impl Middleware for TimingMiddleware {
171 /// type Error = BoxHttpError;
172 /// async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
173 /// let start = std::time::Instant::now();
174 ///
175 /// // Call the next middleware or endpoint
176 /// let response = next.respond(request).await.map_err(MiddlewareError::Endpoint)?;
177 ///
178 /// let duration = start.elapsed();
179 /// println!("Request processed in {:?}", duration);
180 ///
181 /// Ok(response)
182 /// }
183 /// }
184 /// ```
185 fn handle<E: Endpoint>(
186 &mut self,
187 request: &mut Request,
188 next: E,
189 ) -> impl Future<Output = Result<Response, MiddlewareError<E::Error, Self::Error>>> + Send;
190}
191
192/// Error type for middleware that can represent errors from either the middleware itself or the endpoint it wraps.
193#[derive(Debug)]
194pub enum MiddlewareError<N, E> {
195 /// Error originating from the endpoint being called.
196 Endpoint(N),
197 /// Error originating from the middleware itself.
198 Middleware(E),
199}
200
201impl<N: HttpError, E: HttpError> Display for MiddlewareError<N, E> {
202 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203 match self {
204 MiddlewareError::Endpoint(e) => write!(f, "Endpoint error: {}", e),
205 MiddlewareError::Middleware(e) => write!(f, "Middleware error: {}", e),
206 }
207 }
208}
209
210impl<N: HttpError, E: HttpError> core::error::Error for MiddlewareError<N, E> {
211 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
212 match self {
213 MiddlewareError::Endpoint(e) => e.source(),
214 MiddlewareError::Middleware(e) => e.source(),
215 }
216 }
217}
218
219impl<N: HttpError, E: HttpError> HttpError for MiddlewareError<N, E> {
220 fn status(&self) -> StatusCode {
221 match self {
222 MiddlewareError::Endpoint(e) => e.status(),
223 MiddlewareError::Middleware(e) => e.status(),
224 }
225 }
226}
227
228pub(crate) trait MiddlewareImpl: Send {
229 fn handle_inner<'this, 'req, 'next, 'fut>(
230 &'this mut self,
231 request: &'req mut Request,
232 next: &'next mut dyn EndpointImpl,
233 ) -> Pin<Box<dyn 'fut + Future<Output = Result<Response, BoxHttpError>> + Send>>
234 where
235 'this: 'fut,
236 'req: 'fut,
237 'next: 'fut;
238 fn name(&self) -> &'static str {
239 type_name::<Self>()
240 }
241}
242
243impl<'a> Endpoint for &mut (dyn EndpointImpl + 'a) {
244 type Error = BoxHttpError;
245 async fn respond(&mut self, request: &mut Request) -> Result<Response, Self::Error> {
246 self.respond_inner(request).await
247 }
248}
249
250impl<T: Middleware> MiddlewareImpl for T {
251 fn handle_inner<'this, 'req, 'next, 'fut>(
252 &'this mut self,
253 request: &'req mut Request,
254 next: &'next mut dyn EndpointImpl,
255 ) -> Pin<Box<dyn 'fut + Future<Output = Result<Response, BoxHttpError>> + Send>>
256 where
257 'this: 'fut,
258 'req: 'fut,
259 'next: 'fut,
260 {
261 Box::pin(async move {
262 self.handle(request, next)
263 .await
264 .map_err(|e| Box::new(e) as BoxHttpError)
265 })
266 }
267}
268
269impl<M: Middleware> Middleware for &mut M {
270 type Error = M::Error;
271 async fn handle<E: Endpoint>(
272 &mut self,
273 request: &mut Request,
274 next: E,
275 ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
276 Middleware::handle(*self, request, next).await
277 }
278}
279
280impl<M: Middleware> Middleware for Box<M> {
281 type Error = M::Error;
282 async fn handle<E: Endpoint>(
283 &mut self,
284 request: &mut Request,
285 next: E,
286 ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
287 Middleware::handle(self.deref_mut(), request, next).await
288 }
289}
290
291/// Error type for middleware tuples, representing errors from either middleware.
292#[derive(Debug)]
293pub enum MiddlewareTupleError<E1: HttpError, E2: HttpError> {
294 /// Error from the first middleware in the tuple.
295 First(E1),
296 /// Error from the second middleware in the tuple.
297 Second(E2),
298}
299
300impl<A, B> Display for MiddlewareTupleError<A, B>
301where
302 A: HttpError,
303 B: HttpError,
304{
305 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
306 match self {
307 MiddlewareTupleError::First(e) => write!(f, "First middleware error: {}", e),
308 MiddlewareTupleError::Second(e) => write!(f, "Second middleware error: {}", e),
309 }
310 }
311}
312
313impl<A, B> core::error::Error for MiddlewareTupleError<A, B>
314where
315 A: HttpError,
316 B: HttpError,
317{
318 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
319 match self {
320 MiddlewareTupleError::First(e) => e.source(),
321 MiddlewareTupleError::Second(e) => e.source(),
322 }
323 }
324}
325
326impl<A, B> HttpError for MiddlewareTupleError<A, B>
327where
328 A: HttpError,
329 B: HttpError,
330{
331 fn status(&self) -> StatusCode {
332 match self {
333 MiddlewareTupleError::First(e) => e.status(),
334 MiddlewareTupleError::Second(e) => e.status(),
335 }
336 }
337}
338
339/// Type-erased middleware that can hold any middleware implementation behind a trait object.
340///
341/// `AnyMiddleware` provides dynamic dispatch for middleware, allowing you to store
342/// different middleware types in the same collection or pass them around without
343/// knowing their concrete types at compile time. This is particularly useful for:
344///
345/// - Building flexible middleware chains with different middleware types
346/// - Plugin systems where middleware is loaded dynamically
347/// - Configuration-driven middleware stacks
348/// - Storing middleware in collections or registries
349pub struct AnyMiddleware(Box<dyn MiddlewareImpl>);
350
351impl Debug for AnyMiddleware {
352 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
353 f.write_fmt(format_args!("AnyMiddleware[{}]", self.name()))
354 }
355}
356
357impl AnyMiddleware {
358 /// Creates a new type-erased middleware wrapper around the given middleware implementation.
359 ///
360 /// This method takes any type that implements `Middleware` and wraps it in an
361 /// `AnyMiddleware` that can be stored alongside other middleware of different types.
362 /// The original middleware type information is erased, but the functionality is preserved.
363 ///
364 /// # Arguments
365 ///
366 /// * `middleware` - Any middleware implementation
367 ///
368 /// # Examples
369 ///
370 /// ```rust
371 /// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, BoxHttpError};
372 /// use http_kit::middleware::MiddlewareError;
373 ///
374 /// struct CustomMiddleware {
375 /// prefix: String,
376 /// }
377 ///
378 /// impl Middleware for CustomMiddleware {
379 /// type Error = BoxHttpError;
380 /// async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
381 /// println!("{}: Processing {}", self.prefix, request.uri());
382 /// next.respond(request).await.map_err(MiddlewareError::Endpoint)
383 /// }
384 /// }
385 ///
386 /// let middleware = CustomMiddleware { prefix: "API".to_string() };
387 /// let any_middleware = AnyMiddleware::new(middleware);
388 /// ```
389 pub fn new(middleware: impl Middleware + 'static) -> Self {
390 AnyMiddleware(Box::new(middleware))
391 }
392
393 /// Returns the type name of the underlying middleware implementation.
394 ///
395 /// This method provides introspection capabilities for debugging, logging,
396 /// or monitoring purposes. The returned string is the fully qualified type name
397 /// of the original middleware type.
398 ///
399 /// # Examples
400 ///
401 /// ```rust
402 /// use http_kit::{Request, Response, Result, Middleware, Endpoint, middleware::AnyMiddleware, Body, BoxHttpError};
403 /// use http_kit::middleware::MiddlewareError;
404 ///
405 /// struct MyMiddleware;
406 /// impl Middleware for MyMiddleware {
407 /// type Error = BoxHttpError;
408 /// async fn handle<E: Endpoint>(&mut self, request: &mut Request, mut next: E) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
409 /// next.respond(request).await.map_err(MiddlewareError::Endpoint)
410 /// }
411 /// }
412 ///
413 /// let any_middleware = AnyMiddleware::new(MyMiddleware);
414 /// println!("Middleware type: {}", any_middleware.name());
415 /// // Output: Middleware type: my_crate::MyMiddleware
416 /// ```
417 pub fn name(&self) -> &'static str {
418 self.0.name()
419 }
420}
421
422impl Middleware for AnyMiddleware {
423 type Error = BoxHttpError;
424 async fn handle<E: Endpoint>(
425 &mut self,
426 request: &mut Request,
427 mut next: E,
428 ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
429 self.0
430 .handle_inner(request, &mut next)
431 .await
432 .map_err(MiddlewareError::<E::Error, _>::Middleware)
433 }
434}
435
436/// No-op middleware implementation for the unit type.
437///
438/// This implementation allows `()` to be used as a middleware that does nothing
439/// but pass the request through to the next handler. This is useful for:
440/// - Default values in generic contexts
441/// - Conditional middleware application
442/// - Testing scenarios where middleware is optional
443impl Middleware for () {
444 type Error = Infallible;
445 async fn handle<E: Endpoint>(
446 &mut self,
447 request: &mut Request,
448 mut next: E,
449 ) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
450 next.respond(request)
451 .await
452 .map_err(MiddlewareError::<_, Self::Error>::Endpoint)
453 }
454}