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;
21use std::pin::Pin;
22use std::sync::Arc;
23
24use crate::handler::BoxHandler;
25use crate::types::BoxMiddleware;
26use crate::types::Request;
27use crate::types::Response;
28
29pub mod basic_auth;
30pub mod bearer_auth;
31pub mod body_limit;
32pub mod jwt_auth;
33
34/// Trait for converting types into middleware functions.
35///
36/// This trait allows various types to be converted into middleware that can be used
37/// in the Tako middleware pipeline. Middleware functions take a request and the next
38/// middleware in the chain, returning a future that resolves to a response.
39///
40/// # Examples
41///
42/// ```rust
43/// use tako::middleware::{IntoMiddleware, Next};
44/// use tako::types::{Request, Response};
45/// use std::{pin::Pin, future::Future};
46///
47/// struct LoggingMiddleware;
48///
49/// impl IntoMiddleware for LoggingMiddleware {
50///     fn into_middleware(
51///         self,
52///     ) -> impl Fn(Request, Next) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
53///     + Clone + Send + Sync + 'static {
54///         |req, next| {
55///             Box::pin(async move {
56///                 println!("Request: {}", req.uri());
57///                 next.run(req).await
58///             })
59///         }
60///     }
61/// }
62/// ```
63#[doc(alias = "middleware")]
64pub trait IntoMiddleware {
65  fn into_middleware(
66    self,
67  ) -> impl Fn(Request, Next) -> Pin<Box<dyn Future<Output = Response> + Send + 'static>>
68  + Clone
69  + Send
70  + Sync
71  + 'static;
72}
73
74/// Represents the next step in the middleware execution chain.
75#[doc(alias = "next")]
76pub struct Next {
77  /// Remaining middlewares to be executed in the chain.
78  pub middlewares: Arc<Vec<BoxMiddleware>>,
79  /// Final endpoint handler to be called after all middlewares.
80  pub endpoint: Arc<BoxHandler>,
81}
82
83impl Next {
84  /// Executes the next middleware or endpoint in the chain.
85  pub async fn run(self, req: Request) -> Response {
86    if let Some((mw, rest)) = self.middlewares.split_first() {
87      let rest = Arc::new(rest.to_vec());
88      mw(
89        req,
90        Next {
91          middlewares: rest,
92          endpoint: self.endpoint.clone(),
93        },
94      )
95      .await
96    } else {
97      self.endpoint.call(req).await
98    }
99  }
100}