logdive_api/router.rs
1//! Axum router construction.
2//!
3//! Extracted from `main.rs` so integration tests can build the same router
4//! the binary uses without duplicating route definitions. The router is
5//! pure data — no I/O happens here; `AppState` carries the configuration
6//! and all I/O is deferred into the handler layer.
7
8use axum::{Router, routing::get};
9
10use crate::handlers::{query_handler, stats_handler};
11use crate::state::AppState;
12
13/// Build the application router with all endpoints wired up.
14///
15/// Caller supplies a fully-constructed [`AppState`]. The returned router
16/// is ready to be handed to `axum::serve` in the binary, or to
17/// `tower::ServiceExt::oneshot` in tests.
18pub fn build_router(state: AppState) -> Router {
19 Router::new()
20 .route("/query", get(query_handler))
21 .route("/stats", get(stats_handler))
22 .with_state(state)
23}
24
25// ---------------------------------------------------------------------------
26// Tests
27// ---------------------------------------------------------------------------
28//
29// The router itself is a thin composition layer; meaningful coverage of its
30// behavior lives in the end-to-end integration tests (milestone 8 Unit D),
31// which exercise actual HTTP requests against a real temporary database.
32// A compile-time smoke test here guards against basic regressions in the
33// wiring without duplicating the integration test surface.
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use std::path::PathBuf;
39
40 #[test]
41 fn build_router_produces_a_router_from_a_valid_state() {
42 let state = AppState::new(PathBuf::from("/tmp/does-not-need-to-exist-yet.db"));
43 let _router: Router = build_router(state);
44 // If this compiles and runs, the type plumbing between AppState,
45 // the handlers, and axum::Router is sound. Real behavior is
46 // validated by the integration test suite.
47 }
48}