1use crate::http::HandlerFunc;
2use crate::router::{Route, Router};
3use futures::future::BoxFuture;
4use http::Method;
5use hyper::Body;
6
7pub trait HttpRouter {
9 fn handle(&mut self, method: Method, path: &str, handler: HandlerFunc) -> anyhow::Result<()>;
10 fn set_not_found_handler(&mut self, handler: HandlerFunc);
11 fn set_not_allowed_handler(&mut self, handler: HandlerFunc);
12 fn dispatch(&self, req: http::Request<Body>) -> BoxFuture<'static, http::Response<Body>>;
13}
14
15impl HttpRouter for Router {
16 fn handle(&mut self, method: Method, path: &str, handler: HandlerFunc) -> anyhow::Result<()> {
17 self.add_route(Route::new(method, path.to_string(), handler))
18 }
19
20 fn set_not_found_handler(&mut self, handler: HandlerFunc) {
21 self.set_not_found_handler(handler);
22 }
23
24 fn set_not_allowed_handler(&mut self, handler: HandlerFunc) {
25 self.set_not_allowed_handler(handler);
26 }
27
28 fn dispatch(&self, req: http::Request<Body>) -> BoxFuture<'static, http::Response<Body>> {
29 let inner = self.clone();
30 Box::pin(async move { inner.dispatch(req).await })
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::middleware::handler;
38 use http::{Method, StatusCode};
39 use hyper::Response;
40 use tokio::runtime::Runtime;
41
42 fn runtime() -> Runtime {
43 Runtime::new().unwrap()
44 }
45
46 fn ok_handler() -> HandlerFunc {
47 handler(|_req: http::Request<Body>| async {
48 Response::builder()
49 .status(StatusCode::OK)
50 .body(Body::empty())
51 .unwrap()
52 })
53 }
54
55 #[test]
56 fn handle_and_dispatch_should_work() {
57 runtime().block_on(async {
58 let mut router = Router::new();
59 router.handle(Method::GET, "/ping", ok_handler()).unwrap();
60 let resp = router
61 .dispatch(
62 http::Request::builder()
63 .method(Method::GET)
64 .uri("/ping")
65 .body(Body::empty())
66 .unwrap(),
67 )
68 .await;
69 assert_eq!(resp.status(), StatusCode::OK);
70 });
71 }
72
73 #[test]
74 fn custom_not_found_should_fire() {
75 runtime().block_on(async {
76 let mut router = Router::new();
77 router.set_not_found_handler(handler(|_req: http::Request<Body>| async {
78 Response::builder()
79 .status(StatusCode::IM_A_TEAPOT)
80 .body(Body::empty())
81 .unwrap()
82 }));
83 let resp = router
84 .dispatch(
85 http::Request::builder()
86 .method(Method::GET)
87 .uri("/missing")
88 .body(Body::empty())
89 .unwrap(),
90 )
91 .await;
92 assert_eq!(resp.status(), StatusCode::IM_A_TEAPOT);
93 });
94 }
95}