micro_web/
handler.rs

1//! Request handler types and traits for the web framework.
2//!
3//! This module provides the core abstractions for handling HTTP requests:
4//! - `RequestHandler` trait for implementing request handlers
5//! - `FnHandler` for wrapping async functions as handlers
6//! - Helper functions for creating handlers
7
8use crate::body::ResponseBody;
9use crate::fn_trait::FnTrait;
10
11use crate::responder::Responder;
12use crate::{OptionReqBody, RequestContext};
13use async_trait::async_trait;
14use http::Response;
15
16use crate::extract::FromRequest;
17use std::marker::PhantomData;
18
19pub mod handler_decorator;
20pub mod handler_decorator_factory;
21
22/// Trait for types that can handle HTTP requests.
23///
24/// Implementors must provide an `invoke` method that processes the request
25/// and returns a response. This is the core trait for request handling.
26#[async_trait]
27pub trait RequestHandler: Send + Sync {
28    async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody>;
29}
30
31#[async_trait]
32impl<T> RequestHandler for Box<T>
33where
34    T: RequestHandler,
35{
36    async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
37        (**self).invoke(req, req_body).await
38    }
39}
40
41#[async_trait]
42impl RequestHandler for Box<dyn RequestHandler> {
43    async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
44        (**self).invoke(req, req_body).await
45    }
46}
47
48#[async_trait]
49impl RequestHandler for &dyn RequestHandler {
50    async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
51        (**self).invoke(req, req_body).await
52    }
53}
54
55/// A wrapper type that converts async functions into request handlers.
56///
57/// This allows regular async functions to be used as request handlers
58/// by implementing the `RequestHandler` trait for them.
59///
60/// Type parameters:
61/// - `F`: The async function type
62/// - `Args`: The function arguments type
63pub struct FnHandler<F, Args> {
64    f: F,
65    _phantom: PhantomData<fn(Args)>,
66}
67
68impl<F, Args> FnHandler<F, Args>
69where
70    F: FnTrait<Args>,
71{
72    fn new(f: F) -> Self {
73        Self { f, _phantom: PhantomData }
74    }
75}
76
77/// Creates a new `FnHandler` that wraps the given async function.
78///
79/// This is the main way to convert an async function into a request handler.
80pub fn handler_fn<F, Args>(f: F) -> FnHandler<F, Args>
81where
82    F: FnTrait<Args>,
83{
84    FnHandler::new(f)
85}
86
87#[async_trait]
88impl<F, Args> RequestHandler for FnHandler<F, Args>
89where
90    // Args must implement [`FromRequest`] trait
91    // This allows extracting the function arguments from the HTTP request
92    Args: FromRequest,
93    // F must be a function [`FnTrait`] that can accept Args::Output<'r> for any lifetime 'r
94    // This allows the function to work with arguments that have different lifetimes
95    for<'r> F: FnTrait<Args::Output<'r>>,
96    // The output of calling F must implement [`Responder`] trait
97    // This ensures the function's return value can be converted into an HTTP response
98    for<'r> <F as FnTrait<Args::Output<'r>>>::Output: Responder,
99{
100    async fn invoke<'server, 'req>(&self, req: &mut RequestContext<'server, 'req>, req_body: OptionReqBody) -> Response<ResponseBody> {
101        let args = match Args::from_request(req, req_body.clone()).await {
102            Ok(args) => args,
103            Err(responder) => return responder.response_to(req),
104        };
105        let responder = self.f.call(args).await;
106        responder.response_to(req)
107    }
108}
109
110#[cfg(test)]
111mod test {
112    use crate::fn_trait::FnTrait;
113    use crate::handler::{FnHandler, RequestHandler};
114
115    use http::Method;
116
117    fn assert_is_fn_handler<H: FnTrait<Args>, Args>(_handler: &FnHandler<H, Args>) {
118        // no op
119    }
120
121    fn assert_is_handler<T: RequestHandler>(_handler: &T) {
122        // no op
123    }
124
125    #[test]
126    fn assert_fn_is_http_handler_1() {
127        async fn get(_header: Method) {}
128
129        let http_handler = FnHandler::new(get);
130        assert_is_fn_handler(&http_handler);
131        assert_is_handler(&http_handler);
132    }
133
134    #[test]
135    fn assert_fn_is_http_handler_2() {
136        async fn get(_header: &Method, _str: String) {}
137
138        let http_handler = FnHandler::new(get);
139        assert_is_fn_handler(&http_handler);
140        assert_is_handler(&http_handler);
141    }
142}