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}