elif_http/server/
server.rs

1//! # Elif HTTP Server
2//!
3//! A NestJS-like HTTP server that provides a clean, intuitive API while using Axum under the hood.
4//! Users interact only with framework types - Axum is completely abstracted away.
5
6use super::lifecycle::{build_internal_router, start_server};
7use crate::{
8    config::HttpConfig,
9    errors::{HttpError, HttpResult},
10    middleware::v2::{Middleware, MiddlewarePipelineV2},
11    routing::ElifRouter,
12};
13use elif_core::container::IocContainer;
14use std::net::SocketAddr;
15use std::sync::Arc;
16use tracing::info;
17
18/// The main HTTP server - NestJS-like experience
19///
20/// # Example
21///
22/// ```rust,no_run
23/// use elif_http::{Server, HttpConfig};
24/// use elif_core::container::{IocContainer, ServiceBinder};
25/// use std::sync::Arc;
26///
27/// #[tokio::main]
28/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
29///     let mut container = IocContainer::new();
30///     container.build().unwrap();
31///     let server = Server::new(container, HttpConfig::default())?;
32///     server.listen("0.0.0.0:3000").await?;
33///     Ok(())
34/// }
35/// ```
36pub struct Server {
37    container: Arc<IocContainer>,
38    config: HttpConfig,
39    router: Option<ElifRouter>,
40    middleware: MiddlewarePipelineV2,
41}
42
43impl Server {
44    /// Create a new server instance
45    pub fn new(container: IocContainer, config: HttpConfig) -> HttpResult<Self> {
46        Ok(Self {
47            container: Arc::new(container),
48            config,
49            router: None,
50            middleware: MiddlewarePipelineV2::new(),
51        })
52    }
53
54    /// Create a new server with existing Arc<IocContainer>
55    pub fn with_container(container: Arc<IocContainer>, config: HttpConfig) -> HttpResult<Self> {
56        Ok(Self {
57            container,
58            config,
59            router: None,
60            middleware: MiddlewarePipelineV2::new(),
61        })
62    }
63
64    /// Set custom routes using framework router
65    ///
66    /// # Example
67    ///
68    /// ```rust,no_run
69    /// use elif_http::{Server, ElifRouter, HttpConfig, ElifRequest, HttpResult};
70    /// use elif_core::container::{IocContainer, ServiceBinder};
71    /// use std::sync::Arc;
72    ///
73    /// # async fn get_users(_req: ElifRequest) -> HttpResult<&'static str> { Ok("users") }
74    /// # async fn create_user(_req: ElifRequest) -> HttpResult<&'static str> { Ok("created") }
75    ///
76    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
77    /// let mut container = IocContainer::new();
78    /// container.build().unwrap();
79    /// let mut server = Server::new(container, HttpConfig::default())?;
80    ///
81    /// let router = ElifRouter::new()
82    ///     .get("/users", get_users)
83    ///     .post("/users", create_user);
84    ///
85    /// server.use_router(router);
86    /// # Ok(())
87    /// # }
88    /// ```
89    pub fn use_router(&mut self, router: ElifRouter) -> &mut Self {
90        self.router = Some(router);
91        self
92    }
93
94    /// Add middleware to the server
95    ///
96    /// # Example
97    ///
98    /// ```rust,no_run
99    /// use elif_http::{Server, HttpConfig};
100    /// use elif_core::container::{IocContainer, ServiceBinder};
101    /// use std::sync::Arc;
102    ///
103    /// # #[derive(Debug)]
104    /// # struct LoggingMiddleware;
105    /// # impl LoggingMiddleware {
106    /// #     fn default() -> Self { LoggingMiddleware }
107    /// # }
108    /// # impl elif_http::Middleware for LoggingMiddleware {
109    /// #     fn handle(&self, request: elif_http::ElifRequest, next: elif_http::Next) -> std::pin::Pin<Box<dyn std::future::Future<Output = elif_http::ElifResponse> + Send + 'static>> {
110    /// #         next.call(request)
111    /// #     }
112    /// # }
113    ///
114    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
115    /// let mut container = IocContainer::new();
116    /// container.build().unwrap();
117    /// let mut server = Server::new(container, HttpConfig::default())?;
118    /// server.use_middleware(LoggingMiddleware::default());
119    /// # Ok(())
120    /// # }
121    /// ```
122    pub fn use_middleware<M>(&mut self, middleware: M) -> &mut Self
123    where
124        M: Middleware + 'static,
125    {
126        self.middleware.add_mut(middleware);
127        self
128    }
129
130    /// Enable debug mode for detailed middleware execution logs
131    ///
132    /// # Example
133    ///
134    /// ```rust,no_run
135    /// use elif_http::{Server, HttpConfig};
136    /// use elif_core::container::{IocContainer, ServiceBinder};
137    ///
138    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
139    /// let mut container = IocContainer::new();
140    /// container.build().unwrap();
141    /// let mut server = Server::new(container, HttpConfig::default())?;
142    /// server.debug_middleware(true);
143    /// # Ok(())
144    /// # }
145    /// ```
146    pub fn debug_middleware(&mut self, enable: bool) -> &mut Self {
147        if enable {
148            // Convert current pipeline to debug pipeline (for future use)
149            let _debug_pipeline = self.middleware.clone().with_debug();
150            println!("šŸ› Middleware debug mode enabled");
151            println!("   Middleware chain: {:?}", self.middleware.names());
152        } else {
153            println!("šŸ”‡ Middleware debug mode disabled");
154        }
155        self
156    }
157
158    /// Inspect all registered middleware and show execution order
159    ///
160    /// # Example
161    ///
162    /// ```rust,no_run
163    /// use elif_http::{Server, HttpConfig};
164    /// use elif_core::container::{IocContainer, ServiceBinder};
165    ///
166    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
167    /// let mut container = IocContainer::new();
168    /// container.build().unwrap();
169    /// let server = Server::new(container, HttpConfig::default())?;
170    /// server.inspect_middleware();
171    /// # Ok(())
172    /// # }
173    /// ```
174    pub fn inspect_middleware(&self) {
175        let info = self.middleware.debug_info();
176
177        println!("šŸ” Middleware Pipeline Inspection");
178        println!("   Total middleware: {}", info.middleware_count);
179
180        if info.middleware_count == 0 {
181            println!("   No middleware registered");
182            return;
183        }
184
185        println!("   Execution order:");
186        for (index, name) in info.middleware_names.iter().enumerate() {
187            println!("     {}. {}", index + 1, name);
188        }
189
190        println!("\nšŸ’” Tip: Use debug_middleware(true) for runtime execution logs");
191    }
192
193    /// Add profiler middleware to log timing for each request
194    ///
195    /// # Example
196    ///
197    /// ```rust,no_run
198    /// use elif_http::{Server, HttpConfig};
199    /// use elif_core::container::{IocContainer, ServiceBinder};
200    ///
201    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
202    /// let mut container = IocContainer::new();
203    /// container.build().unwrap();
204    /// let mut server = Server::new(container, HttpConfig::default())?;
205    /// server.use_profiler();
206    /// # Ok(())
207    /// # }
208    /// ```
209    pub fn use_profiler(&mut self) -> &mut Self {
210        use crate::middleware::v2::ProfilerMiddleware;
211        self.use_middleware(ProfilerMiddleware::new());
212        println!("šŸ“Š Profiler middleware enabled - request timings will be logged");
213        self
214    }
215
216    /// Start the server on the specified address
217    ///
218    /// # Example
219    ///
220    /// ```rust,no_run
221    /// # use elif_http::{Server, HttpConfig};
222    /// # use elif_core::container::IocContainer;
223    /// # use std::sync::Arc;
224    /// #
225    /// # #[tokio::main]
226    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
227    /// #     let mut container = IocContainer::new();
228    /// #     container.build().unwrap();
229    /// #     let server = Server::new(container, HttpConfig::default())?;
230    /// server.listen("0.0.0.0:3000").await?;
231    /// #     Ok(())
232    /// # }
233    /// ```
234    pub async fn listen<A: Into<String>>(self, addr: A) -> HttpResult<()> {
235        let addr_str = addr.into();
236        let socket_addr: SocketAddr = addr_str
237            .parse()
238            .map_err(|e| HttpError::config(format!("Invalid address '{}': {}", addr_str, e)))?;
239
240        self.listen_on(socket_addr).await
241    }
242
243    /// Start the server on the specified SocketAddr
244    pub async fn listen_on(self, addr: SocketAddr) -> HttpResult<()> {
245        info!("šŸš€ Starting Elif server on {}", addr);
246        info!(
247            "šŸ“‹ Health check endpoint: {}",
248            self.config.health_check_path
249        );
250
251        // Build the internal router
252        let axum_router = build_internal_router(
253            self.container.clone(),
254            self.config.clone(),
255            self.router,
256            self.middleware,
257        )
258        .await?;
259
260        // Start the server
261        start_server(addr, axum_router).await?;
262
263        info!("šŸ›‘ Server shut down gracefully");
264        Ok(())
265    }
266
267    // Getter methods for testing and inspection
268    pub fn container(&self) -> &Arc<IocContainer> {
269        &self.container
270    }
271
272    pub fn config(&self) -> &HttpConfig {
273        &self.config
274    }
275
276    pub fn router(&self) -> Option<&ElifRouter> {
277        self.router.as_ref()
278    }
279
280    pub fn middleware(&self) -> &MiddlewarePipelineV2 {
281        &self.middleware
282    }
283}
284
285#[cfg(test)]
286mod tests {
287    use super::*;
288    use crate::testing::create_test_container;
289
290    #[test]
291    fn test_server_creation() {
292        let container = create_test_container();
293        let config = HttpConfig::default();
294
295        let server = Server::with_container(container, config);
296        assert!(server.is_ok());
297    }
298
299    #[test]
300    fn test_server_with_arc_container() {
301        let container = create_test_container();
302        let config = HttpConfig::default();
303
304        let server = Server::with_container(container, config);
305        assert!(server.is_ok());
306    }
307
308    #[test]
309    fn test_server_configuration() {
310        let container = create_test_container();
311        let config = HttpConfig::default();
312        let server = Server::with_container(container, config).unwrap();
313
314        assert_eq!(server.config().health_check_path, "/health");
315    }
316
317    #[test]
318    fn test_middleware_debugging_tools() {
319        let container = create_test_container();
320        let config = HttpConfig::default();
321        let mut server = Server::with_container(container, config).unwrap();
322
323        // Add some middleware
324        server
325            .use_middleware(crate::middleware::v2::LoggingMiddleware)
326            .use_middleware(crate::middleware::v2::factories::cors())
327            .use_profiler();
328
329        // Test inspect_middleware - should not panic
330        server.inspect_middleware();
331
332        // Test debug_middleware - should not panic
333        server.debug_middleware(true);
334        server.debug_middleware(false);
335
336        // Verify middleware count
337        assert_eq!(server.middleware().len(), 3); // LoggingMiddleware + CorsMiddleware + ProfilerMiddleware
338    }
339}