rustapi_core/
handler.rs

1//! Handler trait and utilities
2
3use crate::extract::FromRequest;
4use crate::request::Request;
5use crate::response::{IntoResponse, Response};
6use rustapi_openapi::{Operation, OperationModifier, ResponseModifier};
7use std::future::Future;
8use std::marker::PhantomData;
9use std::pin::Pin;
10
11/// Trait representing an async handler function
12pub trait Handler<T>: Clone + Send + Sync + Sized + 'static {
13    /// The response type
14    type Future: Future<Output = Response> + Send + 'static;
15
16    /// Call the handler with the request
17    fn call(self, req: Request) -> Self::Future;
18    
19    /// Update the OpenAPI operation
20    fn update_operation(op: &mut Operation);
21}
22
23/// Wrapper to convert a Handler into a tower Service
24pub struct HandlerService<H, T> {
25    handler: H,
26    _marker: PhantomData<fn() -> T>,
27}
28
29impl<H, T> HandlerService<H, T> {
30    pub fn new(handler: H) -> Self {
31        Self {
32            handler,
33            _marker: PhantomData,
34        }
35    }
36}
37
38impl<H: Clone, T> Clone for HandlerService<H, T> {
39    fn clone(&self) -> Self {
40        Self {
41            handler: self.handler.clone(),
42            _marker: PhantomData,
43        }
44    }
45}
46
47// Implement Handler for async functions with 0-6 extractors
48
49// 0 args
50impl<F, Fut, Res> Handler<()> for F
51where
52    F: FnOnce() -> Fut + Clone + Send + Sync + 'static,
53    Fut: Future<Output = Res> + Send + 'static,
54    Res: IntoResponse + ResponseModifier,
55{
56    type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
57
58    fn call(self, _req: Request) -> Self::Future {
59        Box::pin(async move {
60            self().await.into_response()
61        })
62    }
63    
64    fn update_operation(op: &mut Operation) {
65        Res::update_response(op);
66    }
67}
68
69// 1 arg
70impl<F, Fut, Res, T1> Handler<(T1,)> for F
71where
72    F: FnOnce(T1) -> Fut + Clone + Send + Sync + 'static,
73    Fut: Future<Output = Res> + Send + 'static,
74    Res: IntoResponse + ResponseModifier,
75    T1: FromRequest + OperationModifier + Send + 'static,
76{
77    type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
78
79    fn call(self, mut req: Request) -> Self::Future {
80        Box::pin(async move {
81            let t1 = match T1::from_request(&mut req).await {
82                Ok(v) => v,
83                Err(e) => return e.into_response(),
84            };
85            self(t1).await.into_response()
86        })
87    }
88    
89    fn update_operation(op: &mut Operation) {
90        T1::update_operation(op);
91        Res::update_response(op);
92    }
93}
94
95// 2 args
96impl<F, Fut, Res, T1, T2> Handler<(T1, T2)> for F
97where
98    F: FnOnce(T1, T2) -> Fut + Clone + Send + Sync + 'static,
99    Fut: Future<Output = Res> + Send + 'static,
100    Res: IntoResponse + ResponseModifier,
101    T1: FromRequest + OperationModifier + Send + 'static,
102    T2: FromRequest + OperationModifier + Send + 'static,
103{
104    type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
105
106    fn call(self, mut req: Request) -> Self::Future {
107        Box::pin(async move {
108            let t1 = match T1::from_request(&mut req).await {
109                Ok(v) => v,
110                Err(e) => return e.into_response(),
111            };
112            let t2 = match T2::from_request(&mut req).await {
113                Ok(v) => v,
114                Err(e) => return e.into_response(),
115            };
116            self(t1, t2).await.into_response()
117        })
118    }
119    
120    fn update_operation(op: &mut Operation) {
121        T1::update_operation(op);
122        T2::update_operation(op);
123        Res::update_response(op);
124    }
125}
126
127// 3 args
128impl<F, Fut, Res, T1, T2, T3> Handler<(T1, T2, T3)> for F
129where
130    F: FnOnce(T1, T2, T3) -> Fut + Clone + Send + Sync + 'static,
131    Fut: Future<Output = Res> + Send + 'static,
132    Res: IntoResponse + ResponseModifier,
133    T1: FromRequest + OperationModifier + Send + 'static,
134    T2: FromRequest + OperationModifier + Send + 'static,
135    T3: FromRequest + OperationModifier + Send + 'static,
136{
137    type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
138
139    fn call(self, mut req: Request) -> Self::Future {
140        Box::pin(async move {
141            let t1 = match T1::from_request(&mut req).await {
142                Ok(v) => v,
143                Err(e) => return e.into_response(),
144            };
145            let t2 = match T2::from_request(&mut req).await {
146                Ok(v) => v,
147                Err(e) => return e.into_response(),
148            };
149            let t3 = match T3::from_request(&mut req).await {
150                Ok(v) => v,
151                Err(e) => return e.into_response(),
152            };
153            self(t1, t2, t3).await.into_response()
154        })
155    }
156    
157    fn update_operation(op: &mut Operation) {
158        T1::update_operation(op);
159        T2::update_operation(op);
160        T3::update_operation(op);
161        Res::update_response(op);
162    }
163}
164
165// 4 args
166impl<F, Fut, Res, T1, T2, T3, T4> Handler<(T1, T2, T3, T4)> for F
167where
168    F: FnOnce(T1, T2, T3, T4) -> Fut + Clone + Send + Sync + 'static,
169    Fut: Future<Output = Res> + Send + 'static,
170    Res: IntoResponse + ResponseModifier,
171    T1: FromRequest + OperationModifier + Send + 'static,
172    T2: FromRequest + OperationModifier + Send + 'static,
173    T3: FromRequest + OperationModifier + Send + 'static,
174    T4: FromRequest + OperationModifier + Send + 'static,
175{
176    type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
177
178    fn call(self, mut req: Request) -> Self::Future {
179        Box::pin(async move {
180            let t1 = match T1::from_request(&mut req).await {
181                Ok(v) => v,
182                Err(e) => return e.into_response(),
183            };
184            let t2 = match T2::from_request(&mut req).await {
185                Ok(v) => v,
186                Err(e) => return e.into_response(),
187            };
188            let t3 = match T3::from_request(&mut req).await {
189                Ok(v) => v,
190                Err(e) => return e.into_response(),
191            };
192            let t4 = match T4::from_request(&mut req).await {
193                Ok(v) => v,
194                Err(e) => return e.into_response(),
195            };
196            self(t1, t2, t3, t4).await.into_response()
197        })
198    }
199    
200    fn update_operation(op: &mut Operation) {
201        T1::update_operation(op);
202        T2::update_operation(op);
203        T3::update_operation(op);
204        T4::update_operation(op);
205        Res::update_response(op);
206    }
207}
208
209// 5 args
210impl<F, Fut, Res, T1, T2, T3, T4, T5> Handler<(T1, T2, T3, T4, T5)> for F
211where
212    F: FnOnce(T1, T2, T3, T4, T5) -> Fut + Clone + Send + Sync + 'static,
213    Fut: Future<Output = Res> + Send + 'static,
214    Res: IntoResponse + ResponseModifier,
215    T1: FromRequest + OperationModifier + Send + 'static,
216    T2: FromRequest + OperationModifier + Send + 'static,
217    T3: FromRequest + OperationModifier + Send + 'static,
218    T4: FromRequest + OperationModifier + Send + 'static,
219    T5: FromRequest + OperationModifier + Send + 'static,
220{
221    type Future = Pin<Box<dyn Future<Output = Response> + Send>>;
222
223    fn call(self, mut req: Request) -> Self::Future {
224        Box::pin(async move {
225            let t1 = match T1::from_request(&mut req).await {
226                Ok(v) => v,
227                Err(e) => return e.into_response(),
228            };
229            let t2 = match T2::from_request(&mut req).await {
230                Ok(v) => v,
231                Err(e) => return e.into_response(),
232            };
233            let t3 = match T3::from_request(&mut req).await {
234                Ok(v) => v,
235                Err(e) => return e.into_response(),
236            };
237            let t4 = match T4::from_request(&mut req).await {
238                Ok(v) => v,
239                Err(e) => return e.into_response(),
240            };
241            let t5 = match T5::from_request(&mut req).await {
242                Ok(v) => v,
243                Err(e) => return e.into_response(),
244            };
245            self(t1, t2, t3, t4, t5).await.into_response()
246        })
247    }
248    
249    fn update_operation(op: &mut Operation) {
250        T1::update_operation(op);
251        T2::update_operation(op);
252        T3::update_operation(op);
253        T4::update_operation(op);
254        T5::update_operation(op);
255        Res::update_response(op);
256    }
257}
258
259// Type-erased handler for storage in router
260pub(crate) type BoxedHandler = Box<
261    dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync
262>;
263
264/// Create a boxed handler from any Handler
265pub(crate) fn into_boxed_handler<H, T>(handler: H) -> BoxedHandler
266where
267    H: Handler<T>,
268    T: 'static,
269{
270    Box::new(move |req| {
271        let handler = handler.clone();
272        Box::pin(async move {
273            handler.call(req).await
274        })
275    })
276}
277
278/// Trait for handlers with route metadata (generated by #[rustapi::get], etc.)
279///
280/// This trait provides the path and method information for a handler,
281/// allowing `.mount(handler)` to automatically register the route.
282pub trait RouteHandler<T>: Handler<T> {
283    /// The path pattern for this route (e.g., "/users/{id}")
284    const PATH: &'static str;
285    /// The HTTP method for this route (e.g., "GET")
286    const METHOD: &'static str;
287}
288
289/// Represents a route definition that can be registered with .mount()
290pub struct Route {
291    pub(crate) path: &'static str,
292    pub(crate) method: &'static str,
293    pub(crate) handler: BoxedHandler,
294    pub(crate) operation: Operation,
295}
296
297impl Route {
298    /// Create a new route from a handler with path and method
299    pub fn new<H, T>(path: &'static str, method: &'static str, handler: H) -> Self
300    where
301        H: Handler<T>,
302        T: 'static,
303    {
304        let mut operation = Operation::new();
305        H::update_operation(&mut operation);
306        
307        Self {
308            path,
309            method,
310            handler: into_boxed_handler(handler),
311            operation,
312        }
313    }
314    /// Set the operation summary
315    pub fn summary(mut self, summary: impl Into<String>) -> Self {
316        self.operation = self.operation.summary(summary);
317        self
318    }
319
320    /// Set the operation description
321    pub fn description(mut self, description: impl Into<String>) -> Self {
322        self.operation = self.operation.description(description);
323        self
324    }
325
326    /// Add a tag to the operation
327    pub fn tag(mut self, tag: impl Into<String>) -> Self {
328        let tag = tag.into();
329        let mut tags = self.operation.tags.take().unwrap_or_default();
330        tags.push(tag);
331        self.operation.tags = Some(tags);
332        self
333    }
334}
335
336/// Helper macro to create a Route from a handler with RouteHandler trait
337#[macro_export]
338macro_rules! route {
339    ($handler:ident) => {{
340        $crate::Route::new(
341            $handler::PATH,
342            $handler::METHOD,
343            $handler,
344        )
345    }};
346}
347
348/// Create a GET route
349pub fn get_route<H, T>(path: &'static str, handler: H) -> Route
350where
351    H: Handler<T>,
352    T: 'static,
353{
354    Route::new(path, "GET", handler)
355}
356
357/// Create a POST route
358pub fn post_route<H, T>(path: &'static str, handler: H) -> Route
359where
360    H: Handler<T>,
361    T: 'static,
362{
363    Route::new(path, "POST", handler)
364}
365
366/// Create a PUT route
367pub fn put_route<H, T>(path: &'static str, handler: H) -> Route
368where
369    H: Handler<T>,
370    T: 'static,
371{
372    Route::new(path, "PUT", handler)
373}
374
375/// Create a PATCH route 
376pub fn patch_route<H, T>(path: &'static str, handler: H) -> Route
377where
378    H: Handler<T>,
379    T: 'static,
380{
381    Route::new(path, "PATCH", handler)
382}
383
384/// Create a DELETE route
385pub fn delete_route<H, T>(path: &'static str, handler: H) -> Route
386where
387    H: Handler<T>,
388    T: 'static,
389{
390    Route::new(path, "DELETE", handler)
391}