rest/
engine.rs

1use crate::IntoHandler;
2use crate::config::RestConf;
3use crate::http::HandlerFunc;
4use crate::middleware::Middleware;
5use crate::router::Route;
6use crate::server::{Server, ServerHandle};
7
8/// Engine that collects routes/middlewares and then starts the server.
9#[derive(Clone)]
10pub struct Engine {
11    conf: RestConf,
12    routes: Vec<Route>,
13    middlewares: Vec<Middleware>,
14    not_found: Option<HandlerFunc>,
15    not_allowed: Option<HandlerFunc>,
16}
17
18impl Engine {
19    /// Create engine with RestConf; validates config.
20    /// Create engine with RestConf and validate config.
21    pub fn new(conf: RestConf) -> anyhow::Result<Self> {
22        Ok(Self {
23            conf,
24            routes: Vec::new(),
25            middlewares: Vec::new(),
26            not_found: None,
27            not_allowed: None,
28        })
29    }
30
31    /// Panic on invalid config (MustNew-style behavior).
32    pub fn must_new(conf: RestConf) -> Self {
33        Self::new(conf).unwrap()
34    }
35
36    /// Add multiple routes.
37    /// Add multiple routes.
38    pub fn add_routes<I>(&mut self, routes: I)
39    where
40        I: IntoIterator<Item = Route>,
41    {
42        self.routes.extend(routes);
43    }
44
45    /// Add single route.
46    /// Add a single route.
47    pub fn add_route(&mut self, route: Route) {
48        self.routes.push(route);
49    }
50
51    /// Register global middleware.
52    /// Register global middleware.
53    pub fn use_middleware(&mut self, middleware: Middleware) {
54        self.middlewares.push(middleware);
55    }
56
57    /// Set custom 404 handler.
58    /// Set custom 404 handler.
59    pub fn set_not_found_handler(&mut self, handler: impl IntoHandler) {
60        self.not_found = Some(handler.into_handler());
61    }
62
63    /// Set custom 405 handler.
64    /// Set custom 405 handler.
65    pub fn set_not_allowed_handler(&mut self, handler: impl IntoHandler) {
66        self.not_allowed = Some(handler.into_handler());
67    }
68
69    /// Start server with collected routes/middlewares.
70    /// Start server with collected routes and middlewares.
71    pub async fn start(self) -> anyhow::Result<ServerHandle> {
72        let mut server = Server::new(self.conf.clone());
73
74        if let Some(h) = self.not_found.clone() {
75            server.set_not_found_handler(h);
76        }
77        if let Some(h) = self.not_allowed.clone() {
78            server.set_not_allowed_handler(h);
79        }
80        for mw in &self.middlewares {
81            server.use_middleware(mw.clone());
82        }
83        server.add_routes(self.routes.clone());
84        server.start().await
85    }
86
87    /// Print registered routes (method path).
88    /// Print registered routes (method + path).
89    pub fn print_routes(&self) {
90        let mut routes: Vec<String> = self
91            .routes
92            .iter()
93            .map(|r| format!("{} {}", r.method, r.path))
94            .collect();
95        routes.sort();
96        println!("Routes:");
97        for r in routes {
98            println!("  {r}");
99        }
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106    use http::Method;
107    use hyper::{Body, Response};
108
109    fn ok_route(path: &str) -> Route {
110        Route::new(Method::GET, path, |_req: http::Request<Body>| async {
111            Response::new(Body::from("ok"))
112        })
113    }
114
115    #[test]
116    fn add_routes_should_collect() {
117        let mut eng = Engine::must_new(RestConf::default());
118        eng.add_route(ok_route("/a"));
119        eng.add_routes(vec![ok_route("/b"), ok_route("/c")]);
120        assert_eq!(eng.routes.len(), 3);
121    }
122}