rest/http/
router.rs

1use crate::http::HandlerFunc;
2use crate::router::{Route, Router};
3use futures::future::BoxFuture;
4use http::Method;
5use hyper::Body;
6
7/// Router interface abstraction.
8pub 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}