kit_rs/routing/
macros.rs

1//! Route definition macros and helpers for Laravel-like routing syntax
2//!
3//! This module provides a clean, declarative way to define routes:
4//!
5//! ```rust,ignore
6//! use kit::{routes, get, post, put, delete};
7//!
8//! routes! {
9//!     get("/", controllers::home::index).name("home"),
10//!     get("/users", controllers::user::index).name("users.index"),
11//!     post("/users", controllers::user::store).name("users.store"),
12//!     get("/protected", controllers::home::index).middleware(AuthMiddleware),
13//! }
14//! ```
15
16use crate::http::{Request, Response};
17use crate::middleware::{into_boxed, BoxedMiddleware, Middleware};
18use crate::routing::router::Router;
19use std::future::Future;
20
21/// HTTP method for route definitions
22#[derive(Clone, Copy)]
23pub enum HttpMethod {
24    Get,
25    Post,
26    Put,
27    Delete,
28}
29
30/// Builder for route definitions that supports `.name()` and `.middleware()` chaining
31pub struct RouteDefBuilder<H> {
32    method: HttpMethod,
33    path: &'static str,
34    handler: H,
35    name: Option<&'static str>,
36    middlewares: Vec<BoxedMiddleware>,
37}
38
39impl<H, Fut> RouteDefBuilder<H>
40where
41    H: Fn(Request) -> Fut + Send + Sync + 'static,
42    Fut: Future<Output = Response> + Send + 'static,
43{
44    /// Create a new route definition builder
45    pub fn new(method: HttpMethod, path: &'static str, handler: H) -> Self {
46        Self {
47            method,
48            path,
49            handler,
50            name: None,
51            middlewares: Vec::new(),
52        }
53    }
54
55    /// Name this route for URL generation
56    pub fn name(mut self, name: &'static str) -> Self {
57        self.name = Some(name);
58        self
59    }
60
61    /// Add middleware to this route
62    pub fn middleware<M: Middleware + 'static>(mut self, middleware: M) -> Self {
63        self.middlewares.push(into_boxed(middleware));
64        self
65    }
66
67    /// Register this route definition with a router
68    pub fn register(self, router: Router) -> Router {
69        // First, register the route based on method
70        let builder = match self.method {
71            HttpMethod::Get => router.get(self.path, self.handler),
72            HttpMethod::Post => router.post(self.path, self.handler),
73            HttpMethod::Put => router.put(self.path, self.handler),
74            HttpMethod::Delete => router.delete(self.path, self.handler),
75        };
76
77        // Apply any middleware
78        let builder = self
79            .middlewares
80            .into_iter()
81            .fold(builder, |b, m| b.middleware_boxed(m));
82
83        // Apply name if present, otherwise convert to Router
84        if let Some(name) = self.name {
85            builder.name(name)
86        } else {
87            builder.into()
88        }
89    }
90}
91
92/// Create a GET route definition
93///
94/// # Example
95/// ```rust,ignore
96/// get("/users", controllers::user::index).name("users.index")
97/// ```
98pub fn get<H, Fut>(path: &'static str, handler: H) -> RouteDefBuilder<H>
99where
100    H: Fn(Request) -> Fut + Send + Sync + 'static,
101    Fut: Future<Output = Response> + Send + 'static,
102{
103    RouteDefBuilder::new(HttpMethod::Get, path, handler)
104}
105
106/// Create a POST route definition
107///
108/// # Example
109/// ```rust,ignore
110/// post("/users", controllers::user::store).name("users.store")
111/// ```
112pub fn post<H, Fut>(path: &'static str, handler: H) -> RouteDefBuilder<H>
113where
114    H: Fn(Request) -> Fut + Send + Sync + 'static,
115    Fut: Future<Output = Response> + Send + 'static,
116{
117    RouteDefBuilder::new(HttpMethod::Post, path, handler)
118}
119
120/// Create a PUT route definition
121///
122/// # Example
123/// ```rust,ignore
124/// put("/users/{id}", controllers::user::update).name("users.update")
125/// ```
126pub fn put<H, Fut>(path: &'static str, handler: H) -> RouteDefBuilder<H>
127where
128    H: Fn(Request) -> Fut + Send + Sync + 'static,
129    Fut: Future<Output = Response> + Send + 'static,
130{
131    RouteDefBuilder::new(HttpMethod::Put, path, handler)
132}
133
134/// Create a DELETE route definition
135///
136/// # Example
137/// ```rust,ignore
138/// delete("/users/{id}", controllers::user::destroy).name("users.destroy")
139/// ```
140pub fn delete<H, Fut>(path: &'static str, handler: H) -> RouteDefBuilder<H>
141where
142    H: Fn(Request) -> Fut + Send + Sync + 'static,
143    Fut: Future<Output = Response> + Send + 'static,
144{
145    RouteDefBuilder::new(HttpMethod::Delete, path, handler)
146}
147
148/// Define routes with a clean, Laravel-like syntax
149///
150/// This macro generates a `pub fn register() -> Router` function automatically.
151/// Place it at the top level of your `routes.rs` file.
152///
153/// # Example
154/// ```rust,ignore
155/// use kit::{routes, get, post, put, delete};
156/// use crate::controllers;
157/// use crate::middleware::AuthMiddleware;
158///
159/// routes! {
160///     get("/", controllers::home::index).name("home"),
161///     get("/users", controllers::user::index).name("users.index"),
162///     get("/users/{id}", controllers::user::show).name("users.show"),
163///     post("/users", controllers::user::store).name("users.store"),
164///     put("/users/{id}", controllers::user::update).name("users.update"),
165///     delete("/users/{id}", controllers::user::destroy).name("users.destroy"),
166///     get("/protected", controllers::home::index).middleware(AuthMiddleware),
167/// }
168/// ```
169#[macro_export]
170macro_rules! routes {
171    ( $( $route:expr ),* $(,)? ) => {
172        pub fn register() -> $crate::Router {
173            let mut router = $crate::Router::new();
174            $(
175                router = $route.register(router);
176            )*
177            router
178        }
179    };
180}