1use super::definition::RouteDefinition;
2use crate::routing::handler::RouteHandler;
3use crate::{
4 BootRequest, BootResponse, HttpMethod, ModuleRef, OpenApiResponse, Result, SseEvent, Validate,
5 ViewRenderer,
6};
7use futures_core::Stream;
8use serde::de::DeserializeOwned;
9use serde::Serialize;
10use std::future::Future;
11
12impl RouteDefinition {
13 pub fn all<H>(path: impl Into<String>, handler: H) -> Result<Self>
14 where
15 H: RouteHandler,
16 {
17 Self::new(HttpMethod::All, path, handler)
18 }
19
20 pub fn all_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
21 where
22 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
23 H: RouteHandler,
24 {
25 Self::new_scoped(HttpMethod::All, path, factory)
26 }
27
28 pub fn all_json<H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
29 where
30 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
31 Fut: Future<Output = Result<R>> + Send + 'static,
32 R: Serialize + Send + 'static,
33 {
34 Self::all_json_with_status(path, 200, handler)
35 }
36
37 pub fn all_json_with_status<H, Fut, R>(
38 path: impl Into<String>,
39 status: u16,
40 handler: H,
41 ) -> Result<Self>
42 where
43 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
44 Fut: Future<Output = Result<R>> + Send + 'static,
45 R: Serialize + Send + 'static,
46 {
47 Self::json_response_with_status(HttpMethod::All, path, status, handler)
48 }
49
50 pub fn get<H>(path: impl Into<String>, handler: H) -> Result<Self>
51 where
52 H: RouteHandler,
53 {
54 Self::new(HttpMethod::Get, path, handler)
55 }
56
57 pub fn get_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
58 where
59 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
60 H: RouteHandler,
61 {
62 Self::new_scoped(HttpMethod::Get, path, factory)
63 }
64
65 pub fn get_json<H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
66 where
67 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
68 Fut: Future<Output = Result<R>> + Send + 'static,
69 R: Serialize + Send + 'static,
70 {
71 Self::get_json_with_status(path, 200, handler)
72 }
73
74 pub fn get_json_with_status<H, Fut, R>(
75 path: impl Into<String>,
76 status: u16,
77 handler: H,
78 ) -> Result<Self>
79 where
80 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
81 Fut: Future<Output = Result<R>> + Send + 'static,
82 R: Serialize + Send + 'static,
83 {
84 Self::json_response_with_status(HttpMethod::Get, path, status, handler)
85 }
86
87 pub fn get_view<H, Fut, R>(
88 path: impl Into<String>,
89 view: impl Into<String>,
90 handler: H,
91 ) -> Result<Self>
92 where
93 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
94 Fut: Future<Output = Result<R>> + Send + 'static,
95 R: Serialize + Send + 'static,
96 {
97 Self::get_view_with_status(path, view, 200, handler)
98 }
99
100 pub fn get_view_with_status<H, Fut, R>(
101 path: impl Into<String>,
102 view: impl Into<String>,
103 status: u16,
104 handler: H,
105 ) -> Result<Self>
106 where
107 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
108 Fut: Future<Output = Result<R>> + Send + 'static,
109 R: Serialize + Send + 'static,
110 {
111 Self::view_with_status(HttpMethod::Get, path, view, status, handler)
112 }
113
114 pub fn sse<H, Fut, S>(path: impl Into<String>, handler: H) -> Result<Self>
115 where
116 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
117 Fut: Future<Output = Result<S>> + Send + 'static,
118 S: Stream<Item = Result<SseEvent>> + Send + 'static,
119 {
120 Self::new(HttpMethod::Get, path, move |request: BootRequest| {
121 let future = request
122 .require_accepts_event_stream()
123 .map(|()| handler(request));
124 async move {
125 let stream = future?.await?;
126 Ok(BootResponse::sse(stream))
127 }
128 })
129 }
130
131 pub fn post<H>(path: impl Into<String>, handler: H) -> Result<Self>
132 where
133 H: RouteHandler,
134 {
135 Self::new(HttpMethod::Post, path, handler)
136 }
137
138 pub fn post_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
139 where
140 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
141 H: RouteHandler,
142 {
143 Self::new_scoped(HttpMethod::Post, path, factory)
144 }
145
146 pub fn post_json<T, H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
147 where
148 T: DeserializeOwned + Send + 'static,
149 H: Fn(T) -> Fut + Send + Sync + 'static,
150 Fut: Future<Output = Result<R>> + Send + 'static,
151 R: Serialize + Send + 'static,
152 {
153 Self::post_json_with_status(path, 200, handler)
154 }
155
156 pub fn post_json_with_status<T, H, Fut, R>(
157 path: impl Into<String>,
158 status: u16,
159 handler: H,
160 ) -> Result<Self>
161 where
162 T: DeserializeOwned + Send + 'static,
163 H: Fn(T) -> Fut + Send + Sync + 'static,
164 Fut: Future<Output = Result<R>> + Send + 'static,
165 R: Serialize + Send + 'static,
166 {
167 Self::json_with_status(HttpMethod::Post, path, status, handler)
168 }
169
170 pub fn post_view<H, Fut, R>(
171 path: impl Into<String>,
172 view: impl Into<String>,
173 handler: H,
174 ) -> Result<Self>
175 where
176 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
177 Fut: Future<Output = Result<R>> + Send + 'static,
178 R: Serialize + Send + 'static,
179 {
180 Self::post_view_with_status(path, view, 200, handler)
181 }
182
183 pub fn post_view_with_status<H, Fut, R>(
184 path: impl Into<String>,
185 view: impl Into<String>,
186 status: u16,
187 handler: H,
188 ) -> Result<Self>
189 where
190 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
191 Fut: Future<Output = Result<R>> + Send + 'static,
192 R: Serialize + Send + 'static,
193 {
194 Self::view_with_status(HttpMethod::Post, path, view, status, handler)
195 }
196
197 pub fn post_validated_json<T, H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
198 where
199 T: DeserializeOwned + Validate + Send + 'static,
200 H: Fn(T) -> Fut + Send + Sync + 'static,
201 Fut: Future<Output = Result<R>> + Send + 'static,
202 R: Serialize + Send + 'static,
203 {
204 Self::post_validated_json_with_status(path, 200, handler)
205 }
206
207 pub fn post_validated_json_with_status<T, H, Fut, R>(
208 path: impl Into<String>,
209 status: u16,
210 handler: H,
211 ) -> Result<Self>
212 where
213 T: DeserializeOwned + Validate + Send + 'static,
214 H: Fn(T) -> Fut + Send + Sync + 'static,
215 Fut: Future<Output = Result<R>> + Send + 'static,
216 R: Serialize + Send + 'static,
217 {
218 Self::validated_json_with_status(HttpMethod::Post, path, status, handler)
219 }
220
221 pub fn put<H>(path: impl Into<String>, handler: H) -> Result<Self>
222 where
223 H: RouteHandler,
224 {
225 Self::new(HttpMethod::Put, path, handler)
226 }
227
228 pub fn put_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
229 where
230 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
231 H: RouteHandler,
232 {
233 Self::new_scoped(HttpMethod::Put, path, factory)
234 }
235
236 pub fn put_json<T, H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
237 where
238 T: DeserializeOwned + Send + 'static,
239 H: Fn(T) -> Fut + Send + Sync + 'static,
240 Fut: Future<Output = Result<R>> + Send + 'static,
241 R: Serialize + Send + 'static,
242 {
243 Self::put_json_with_status(path, 200, handler)
244 }
245
246 pub fn put_json_with_status<T, H, Fut, R>(
247 path: impl Into<String>,
248 status: u16,
249 handler: H,
250 ) -> Result<Self>
251 where
252 T: DeserializeOwned + Send + 'static,
253 H: Fn(T) -> Fut + Send + Sync + 'static,
254 Fut: Future<Output = Result<R>> + Send + 'static,
255 R: Serialize + Send + 'static,
256 {
257 Self::json_with_status(HttpMethod::Put, path, status, handler)
258 }
259
260 pub fn put_validated_json<T, H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
261 where
262 T: DeserializeOwned + Validate + Send + 'static,
263 H: Fn(T) -> Fut + Send + Sync + 'static,
264 Fut: Future<Output = Result<R>> + Send + 'static,
265 R: Serialize + Send + 'static,
266 {
267 Self::put_validated_json_with_status(path, 200, handler)
268 }
269
270 pub fn put_validated_json_with_status<T, H, Fut, R>(
271 path: impl Into<String>,
272 status: u16,
273 handler: H,
274 ) -> Result<Self>
275 where
276 T: DeserializeOwned + Validate + Send + 'static,
277 H: Fn(T) -> Fut + Send + Sync + 'static,
278 Fut: Future<Output = Result<R>> + Send + 'static,
279 R: Serialize + Send + 'static,
280 {
281 Self::validated_json_with_status(HttpMethod::Put, path, status, handler)
282 }
283
284 pub fn patch<H>(path: impl Into<String>, handler: H) -> Result<Self>
285 where
286 H: RouteHandler,
287 {
288 Self::new(HttpMethod::Patch, path, handler)
289 }
290
291 pub fn patch_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
292 where
293 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
294 H: RouteHandler,
295 {
296 Self::new_scoped(HttpMethod::Patch, path, factory)
297 }
298
299 pub fn patch_json<T, H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
300 where
301 T: DeserializeOwned + Send + 'static,
302 H: Fn(T) -> Fut + Send + Sync + 'static,
303 Fut: Future<Output = Result<R>> + Send + 'static,
304 R: Serialize + Send + 'static,
305 {
306 Self::patch_json_with_status(path, 200, handler)
307 }
308
309 pub fn patch_json_with_status<T, H, Fut, R>(
310 path: impl Into<String>,
311 status: u16,
312 handler: H,
313 ) -> Result<Self>
314 where
315 T: DeserializeOwned + Send + 'static,
316 H: Fn(T) -> Fut + Send + Sync + 'static,
317 Fut: Future<Output = Result<R>> + Send + 'static,
318 R: Serialize + Send + 'static,
319 {
320 Self::json_with_status(HttpMethod::Patch, path, status, handler)
321 }
322
323 pub fn patch_validated_json<T, H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
324 where
325 T: DeserializeOwned + Validate + Send + 'static,
326 H: Fn(T) -> Fut + Send + Sync + 'static,
327 Fut: Future<Output = Result<R>> + Send + 'static,
328 R: Serialize + Send + 'static,
329 {
330 Self::patch_validated_json_with_status(path, 200, handler)
331 }
332
333 pub fn patch_validated_json_with_status<T, H, Fut, R>(
334 path: impl Into<String>,
335 status: u16,
336 handler: H,
337 ) -> Result<Self>
338 where
339 T: DeserializeOwned + Validate + Send + 'static,
340 H: Fn(T) -> Fut + Send + Sync + 'static,
341 Fut: Future<Output = Result<R>> + Send + 'static,
342 R: Serialize + Send + 'static,
343 {
344 Self::validated_json_with_status(HttpMethod::Patch, path, status, handler)
345 }
346
347 pub fn delete<H>(path: impl Into<String>, handler: H) -> Result<Self>
348 where
349 H: RouteHandler,
350 {
351 Self::new(HttpMethod::Delete, path, handler)
352 }
353
354 pub fn delete_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
355 where
356 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
357 H: RouteHandler,
358 {
359 Self::new_scoped(HttpMethod::Delete, path, factory)
360 }
361
362 pub fn delete_json<H, Fut, R>(path: impl Into<String>, handler: H) -> Result<Self>
363 where
364 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
365 Fut: Future<Output = Result<R>> + Send + 'static,
366 R: Serialize + Send + 'static,
367 {
368 Self::delete_json_with_status(path, 200, handler)
369 }
370
371 pub fn delete_json_with_status<H, Fut, R>(
372 path: impl Into<String>,
373 status: u16,
374 handler: H,
375 ) -> Result<Self>
376 where
377 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
378 Fut: Future<Output = Result<R>> + Send + 'static,
379 R: Serialize + Send + 'static,
380 {
381 Self::json_response_with_status(HttpMethod::Delete, path, status, handler)
382 }
383
384 pub fn options<H>(path: impl Into<String>, handler: H) -> Result<Self>
385 where
386 H: RouteHandler,
387 {
388 Self::new(HttpMethod::Options, path, handler)
389 }
390
391 pub fn options_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
392 where
393 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
394 H: RouteHandler,
395 {
396 Self::new_scoped(HttpMethod::Options, path, factory)
397 }
398
399 pub fn head<H>(path: impl Into<String>, handler: H) -> Result<Self>
400 where
401 H: RouteHandler,
402 {
403 Self::new(HttpMethod::Head, path, handler)
404 }
405
406 pub fn head_scoped<F, H>(path: impl Into<String>, factory: F) -> Result<Self>
407 where
408 F: Fn(&ModuleRef) -> Result<H> + Send + Sync + 'static,
409 H: RouteHandler,
410 {
411 Self::new_scoped(HttpMethod::Head, path, factory)
412 }
413
414 fn json_with_status<T, H, Fut, R>(
415 method: HttpMethod,
416 path: impl Into<String>,
417 status: u16,
418 handler: H,
419 ) -> Result<Self>
420 where
421 T: DeserializeOwned + Send + 'static,
422 H: Fn(T) -> Fut + Send + Sync + 'static,
423 Fut: Future<Output = Result<R>> + Send + 'static,
424 R: Serialize + Send + 'static,
425 {
426 Self::new(method, path, move |request: BootRequest| {
427 let future = request
428 .require_json_content_type()
429 .and_then(|()| request.require_accepts_json())
430 .and_then(|()| request.json::<T>())
431 .map(&handler);
432 async move {
433 let body = future?.await?;
434 BootResponse::json_with_status(status, &body)
435 }
436 })
437 .map(|route| route.with_response(status, OpenApiResponse::description("Success")))
438 }
439
440 fn json_response_with_status<H, Fut, R>(
441 method: HttpMethod,
442 path: impl Into<String>,
443 status: u16,
444 handler: H,
445 ) -> Result<Self>
446 where
447 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
448 Fut: Future<Output = Result<R>> + Send + 'static,
449 R: Serialize + Send + 'static,
450 {
451 Self::new(method, path, move |request: BootRequest| {
452 let future = request.require_accepts_json().map(|()| handler(request));
453 async move {
454 let body = future?.await?;
455 BootResponse::json_with_status(status, &body)
456 }
457 })
458 .map(|route| route.with_response(status, OpenApiResponse::description("Success")))
459 }
460
461 pub fn view<H, Fut, R>(
462 method: HttpMethod,
463 path: impl Into<String>,
464 view: impl Into<String>,
465 handler: H,
466 ) -> Result<Self>
467 where
468 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
469 Fut: Future<Output = Result<R>> + Send + 'static,
470 R: Serialize + Send + 'static,
471 {
472 Self::view_with_status(method, path, view, 200, handler)
473 }
474
475 pub fn view_with_status<H, Fut, R>(
476 method: HttpMethod,
477 path: impl Into<String>,
478 view: impl Into<String>,
479 status: u16,
480 handler: H,
481 ) -> Result<Self>
482 where
483 H: Fn(BootRequest) -> Fut + Send + Sync + 'static,
484 Fut: Future<Output = Result<R>> + Send + 'static,
485 R: Serialize + Send + 'static,
486 {
487 let view = view.into();
488 Self::new(method, path, move |request: BootRequest| {
489 let view = view.clone();
490 let future = request
491 .get::<ViewRenderer>()
492 .map(|renderer| (renderer, handler(request)));
493 async move {
494 let (renderer, future) = future?;
495 let context = future.await?;
496 let context = serde_json::to_value(&context).map_err(|error| {
497 crate::BootError::Internal(format!(
498 "failed to serialize view context `{view}`: {error}"
499 ))
500 })?;
501 renderer
502 .render_value_response_with_status(status, view, context)
503 .await
504 }
505 })
506 .map(|route| route.with_response(status, OpenApiResponse::description("Success")))
507 }
508
509 fn validated_json_with_status<T, H, Fut, R>(
510 method: HttpMethod,
511 path: impl Into<String>,
512 status: u16,
513 handler: H,
514 ) -> Result<Self>
515 where
516 T: DeserializeOwned + Validate + Send + 'static,
517 H: Fn(T) -> Fut + Send + Sync + 'static,
518 Fut: Future<Output = Result<R>> + Send + 'static,
519 R: Serialize + Send + 'static,
520 {
521 Self::json_with_status(method, path, status, handler)
522 .map(|route| route.with_body_validation::<T>().with_validation())
523 }
524}