kit_rs/middleware/mod.rs
1//! Middleware system for Kit framework
2//!
3//! This module provides Laravel 12.x-style middleware support with:
4//! - Global middleware (runs on all routes)
5//! - Route group middleware (shared for a group of routes)
6//! - Per-route middleware (applied to individual routes)
7//!
8//! # Example
9//!
10//! ```rust,ignore
11//! use kit::{async_trait, Middleware, Next, Request, Response, HttpResponse};
12//!
13//! pub struct AuthMiddleware;
14//!
15//! #[async_trait]
16//! impl Middleware for AuthMiddleware {
17//! async fn handle(&self, request: Request, next: Next) -> Response {
18//! if request.header("Authorization").is_none() {
19//! return Err(HttpResponse::text("Unauthorized").status(401));
20//! }
21//! next(request).await
22//! }
23//! }
24//! ```
25
26mod chain;
27mod registry;
28
29pub use chain::MiddlewareChain;
30pub use registry::register_global_middleware;
31pub use registry::MiddlewareRegistry;
32
33use crate::http::{Request, Response};
34use async_trait::async_trait;
35use std::future::Future;
36use std::pin::Pin;
37use std::sync::Arc;
38
39/// Type alias for the boxed future returned by middleware
40pub type MiddlewareFuture = Pin<Box<dyn Future<Output = Response> + Send>>;
41
42/// Type alias for the next handler in the middleware chain
43///
44/// Call `next(request).await` to pass control to the next middleware or the route handler.
45pub type Next = Arc<dyn Fn(Request) -> MiddlewareFuture + Send + Sync>;
46
47/// Type alias for boxed middleware handlers (internal use)
48pub type BoxedMiddleware = Arc<dyn Fn(Request, Next) -> MiddlewareFuture + Send + Sync>;
49
50/// Trait for implementing middleware
51///
52/// Middleware can inspect/modify requests, short-circuit responses, or pass control
53/// to the next middleware in the chain by calling `next(request).await`.
54///
55/// # Example
56///
57/// ```rust,ignore
58/// use kit::{async_trait, Middleware, Next, Request, Response, HttpResponse};
59///
60/// pub struct LoggingMiddleware;
61///
62/// #[async_trait]
63/// impl Middleware for LoggingMiddleware {
64/// async fn handle(&self, request: Request, next: Next) -> Response {
65/// println!("--> {} {}", request.method(), request.path());
66/// let response = next(request).await;
67/// println!("<-- complete");
68/// response
69/// }
70/// }
71/// ```
72#[async_trait]
73pub trait Middleware: Send + Sync {
74 /// Handle the request
75 ///
76 /// - Call `next(request).await` to pass control to the next middleware
77 /// - Return `Err(HttpResponse)` to short-circuit and respond immediately
78 /// - Modify the response after calling `next()` for post-processing
79 async fn handle(&self, request: Request, next: Next) -> Response;
80}
81
82/// Convert a Middleware trait object into a BoxedMiddleware
83pub fn into_boxed<M: Middleware + 'static>(middleware: M) -> BoxedMiddleware {
84 let middleware = Arc::new(middleware);
85 Arc::new(move |req, next| {
86 let mw = middleware.clone();
87 Box::pin(async move { mw.handle(req, next).await })
88 })
89}