rustapi_core/
handler.rs

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