tako/
middleware.rs

1//! Middleware system for request and response processing pipelines.
2//!
3//! This module provides the core middleware infrastructure for Tako, allowing you to
4//! compose request processing pipelines. Middleware can modify requests, responses,
5//! or perform side effects like logging, authentication, or rate limiting. The `Next`
6//! struct manages the execution flow through the middleware chain to the final handler.
7//!
8//! # Examples
9//!
10//! ```rust
11//! use tako::{middleware::Next, types::{Request, Response}};
12//! use std::{pin::Pin, future::Future};
13//!
14//! async fn middleware(req: Request, next: Next) -> Response {
15//!     // Your logic here
16//!     next.run(req).await
17//! }
18//! ```
19
20use std::{future::Future, pin::Pin, sync::Arc};
21
22use crate::{
23  handler::BoxHandler,
24  types::{BoxMiddleware, Request, Response},
25};
26
27pub mod basic_auth;
28pub mod bearer_auth;
29pub mod body_limit;
30pub mod jwt_auth;
31
32/// Trait for converting types into middleware functions.
33///
34/// This trait allows various types to be converted into middleware that can be used
35/// in the Tako middleware pipeline. Middleware functions take a request and the next
36/// middleware in the chain, returning a future that resolves to a response.
37///
38/// # Examples
39///
40/// ```rust
41/// use tako::middleware::{IntoMiddleware, Next};
42/// use tako::types::{Request, Response};
43/// use std::{pin::Pin, future::Future};
44///
45/// struct LoggingMiddleware;
46///
47/// impl IntoMiddleware for LoggingMiddleware {
48///     fn into_middleware(
49///         self,
50///     ) -> impl Fn(Request, Next) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
51///     + Clone + Send + Sync + 'static {
52///         |req, next| {
53///             Box::pin(async move {
54///                 println!("Request: {}", req.uri());
55///                 next.run(req).await
56///             })
57///         }
58///     }
59/// }
60/// ```
61#[doc(alias = "middleware")]
62pub trait IntoMiddleware {
63  fn into_middleware(
64    self,
65  ) -> impl Fn(Request, Next) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
66  + Clone
67  + Send
68  + Sync
69  + 'static;
70}
71
72/// Represents the next step in the middleware execution chain.
73#[doc(alias = "next")]
74pub struct Next {
75  /// Remaining middlewares to be executed in the chain.
76  pub middlewares: Arc<Vec<BoxMiddleware>>,
77  /// Final endpoint handler to be called after all middlewares.
78  pub endpoint: Arc<BoxHandler>,
79}
80
81impl Next {
82  /// Executes the next middleware or endpoint in the chain.
83  pub async fn run(self, req: Request) -> Response {
84    if let Some((mw, rest)) = self.middlewares.split_first() {
85      let rest = Arc::new(rest.to_vec());
86      mw(
87        req,
88        Next {
89          middlewares: rest,
90          endpoint: self.endpoint.clone(),
91        },
92      )
93      .await
94    } else {
95      self.endpoint.call(req).await
96    }
97  }
98}