ripress/router/
mod.rs

1use std::{collections::HashMap, future::Future, sync::Arc};
2
3use crate::{
4    app::{box_future, App},
5    context::{HttpRequest, HttpResponse},
6    types::{Handler, HttpMethods, Routes},
7};
8
9pub struct Router {
10    base_path: String,
11    routes: Routes,
12}
13
14impl Router {
15    pub fn new(base_path: &str) -> Router {
16        return Router {
17            base_path: base_path.to_string(),
18            routes: HashMap::new(),
19        };
20    }
21
22    /// Add a GET route to the router.
23    ///
24    /// ## Arguments
25    ///
26    /// * `path` - The path to the route.
27    /// * `handler` - The handler function for the route.
28    ///
29    /// ## Example
30    ///
31    /// ```
32    /// use ripress::{router::Router, context::{HttpRequest, HttpResponse} };
33    ///
34    /// async fn handler(req: HttpRequest, res: HttpResponse) -> HttpResponse {
35    ///     res.ok().text("Hello, World!")
36    /// }
37    ///
38    /// let mut router = Router::new("/api");
39    /// router.get("/hello", handler);
40    /// ```
41
42    pub fn get<F, Fut>(&mut self, path: &'static str, handler: F)
43    where
44        F: Fn(HttpRequest, HttpResponse) -> Fut + Send + Sync + 'static,
45        Fut: Future<Output = HttpResponse> + Send + 'static,
46    {
47        let wrapped_handler = Arc::new(move |req, res| box_future(handler(req, res)));
48        self.add_route(HttpMethods::GET, path, wrapped_handler);
49    }
50
51    /// Add a POST route to the router.
52    ///
53    /// ## Arguments
54    ///
55    /// * `path` - The path to the route.
56    /// * `handler` - The handler function for the route.
57    ///
58    /// ## Example
59    ///
60    /// ```
61    /// use ripress::{router::Router, context::{HttpRequest, HttpResponse} };
62    ///
63    /// async fn handler(req: HttpRequest, res: HttpResponse) -> HttpResponse {
64    ///     res.ok().text("Hello, World!")
65    /// }
66    ///
67    /// let mut router = Router::new("/api");
68    /// router.post("/hello", handler);
69    /// ```
70
71    pub fn post<F, Fut>(&mut self, path: &'static str, handler: F)
72    where
73        F: Fn(HttpRequest, HttpResponse) -> Fut + Send + Sync + 'static,
74        Fut: Future<Output = HttpResponse> + Send + 'static,
75    {
76        let wrapped_handler = Arc::new(move |req, res| box_future(handler(req, res)));
77        self.add_route(HttpMethods::POST, path, wrapped_handler);
78    }
79
80    /// Add a PUT route to the router.
81    ///
82    /// ## Arguments
83    ///
84    /// * `path` - The path to the route.
85    /// * `handler` - The handler function for the route.
86    ///
87    /// ## Example
88    ///
89    /// ```
90    /// use ripress::{router::Router, context::{HttpRequest, HttpResponse} };
91    ///
92    /// async fn handler(req: HttpRequest, res: HttpResponse) -> HttpResponse {
93    ///     res.ok().text("Hello, World!")
94    /// }
95    ///
96    /// let mut router = Router::new("/api");
97    /// router.put("/hello", handler);
98    /// ```
99
100    pub fn put<F, Fut>(&mut self, path: &'static str, handler: F)
101    where
102        F: Fn(HttpRequest, HttpResponse) -> Fut + Send + Sync + 'static,
103        Fut: Future<Output = HttpResponse> + Send + 'static,
104    {
105        let wrapped_handler = Arc::new(move |req, res| box_future(handler(req, res)));
106        self.add_route(HttpMethods::PUT, path, wrapped_handler);
107    }
108
109    /// Add a DELETE route to the router.
110    ///
111    /// ## Arguments
112    ///
113    /// * `path` - The path to the route.
114    /// * `handler` - The handler function for the route.
115    ///
116    /// ## Example
117    ///
118    /// ```
119    /// use ripress::{router::Router, context::{HttpRequest, HttpResponse} };
120    ///
121    /// async fn handler(req: HttpRequest, res: HttpResponse) -> HttpResponse {
122    ///     res.ok().text("Hello, World!")
123    /// }
124    ///
125    /// let mut router = Router::new("/api");
126    /// router.delete("/hello", handler);
127    /// ```
128
129    pub fn delete<F, Fut>(&mut self, path: &'static str, handler: F)
130    where
131        F: Fn(HttpRequest, HttpResponse) -> Fut + Send + Sync + 'static,
132        Fut: Future<Output = HttpResponse> + Send + 'static,
133    {
134        let wrapped_handler = Arc::new(move |req, res| box_future(handler(req, res)));
135        self.add_route(HttpMethods::DELETE, path, wrapped_handler);
136    }
137
138    /// Add a PATCH route to the router.
139    ///
140    /// ## Arguments
141    ///
142    /// * `path` - The path to the route.
143    /// * `handler` - The handler function for the route.
144    ///
145    /// ## Example
146    ///
147    /// ```
148    /// use ripress::{router::Router, context::{HttpRequest, HttpResponse} };
149    ///
150    /// async fn handler(req: HttpRequest, res: HttpResponse) -> HttpResponse {
151    ///     res.ok().text("Hello, World!")
152    /// }
153    ///
154    /// let mut router = Router::new("/api");
155    /// router.patch("/hello", handler);
156    /// ```
157
158    pub fn patch<F, Fut>(&mut self, path: &'static str, handler: F)
159    where
160        F: Fn(HttpRequest, HttpResponse) -> Fut + Send + Sync + 'static,
161        Fut: Future<Output = HttpResponse> + Send + 'static,
162    {
163        let wrapped_handler = Arc::new(move |req, res| box_future(handler(req, res)));
164        self.add_route(HttpMethods::PATCH, path, wrapped_handler);
165    }
166
167    /// Registers a router with an app.
168    ///
169    /// ## Arguments
170    ///
171    /// * `mut app` - The instance of the app to register the router too
172    ///
173    /// ## Example
174    ///
175    /// ```
176    /// use ripress::{router::Router, context::{HttpRequest, HttpResponse}, app::App};
177    ///
178    /// async fn handler(req: HttpRequest, res: HttpResponse) -> HttpResponse {
179    ///     res.ok().text("Hello, World!")
180    /// }
181    ///
182    /// let mut router = Router::new("/api");
183    /// let mut app = App::new();
184    /// router.patch("/hello", handler);
185    /// router.register(&mut app);
186    /// ```
187
188    pub fn register(self, app: &mut App) {
189        for (path, methods) in self.routes.clone() {
190            for (method, handler) in methods {
191                let full_path = format!("{}{}", self.base_path, path);
192                let path_str = Box::<str>::leak(full_path.into_boxed_str());
193                app.add_route(method, path_str, handler);
194            }
195        }
196    }
197
198    fn add_route(&mut self, method: HttpMethods, path: &'static str, handler: Handler) {
199        let path_handlers = self.routes.entry(path).or_insert_with(HashMap::new);
200        path_handlers.insert(method, handler);
201    }
202}
203
204#[cfg(test)]
205impl Router {
206    pub(crate) fn get_routes(&self, path: &str, method: HttpMethods) -> Option<&Handler> {
207        Some(self.routes.get(path).unwrap().get(&method).unwrap())
208    }
209}