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}