arcature 2026.2.1

Arcature application framework: a high-level Application facade over the certified Arcature subsystems, with the low-level Axum/Tower escape hatch preserved.
Documentation
//! [`Application::into_router`] — extract the assembled Axum router from a
//! built `Application<()>` for in-process or test-hosted serving.
//!
//! This is the test/inspection seam: it runs the post-routing pipeline
//! assembler (the 404 fallback, observe route-layers, error-mapping layer,
//! Inertia layer, maintenance layer) and returns the resulting
//! [`axum::Router<()>`] so a caller can drive it with a real HTTP client —
//! `arcature-test::TestApp::new(router)` being the canonical consumer — or
//! `oneshot` it via [`tower::ServiceExt`] for in-process testing (§78).
//!
//! # What this includes and does not
//!
//! `into_router` returns the **post-routing** router: the route table with
//! the fallback and post-routing layers applied. The **pre-routing** layers
//! (the application proxy and the request-id layer) wrap
//! `router.into_service()` and are applied only by
//! [`Application::serve`](super::ty::Application::serve) /
//! [`Application::run`](super::ty::Application) — they are not part of the
//! `Router` itself (engine spec §7; the proxy is intentionally pre-routing,
//! not a router layer). A test that needs to exercise the application proxy
//! should drive the proxy function directly (it is a pure
//! `Fn(ProxyRequest) -> ProxyAction`) or serve the full application via
//! `Application::serve` on a real listener. `into_router` is the right seam
//! for testing the post-routing pipeline (Inertia redirects, maintenance
//! 503s, 404 fallback, error mapping) through a real socket.
//!
//! # Standalone-first (§16)
//!
//! `into_router` returns a raw [`axum::Router`], so a testing toolkit
//! (`arcature-test`) accepts it without a runtime dependency on `arcature`:
//! the application extracts its router and hands it over. The preferred
//! dependency direction is `arcature` and the testing toolkit both
//! interoperate through Axum — not testing-toolkit → arcature → axum.

use crate::application::ty::Application;
use crate::pipeline::assemble::assemble_router;

impl Application<()> {
    /// Consume the application and return its assembled [`axum::Router<()>`]:
    /// the route table with the 404 fallback and the post-routing layers
    /// (observe, error mapping, Inertia, maintenance) applied.
    ///
    /// This is the test/inspection seam. A testing toolkit such as
    /// `arcature-test` accepts the returned router directly:
    ///
    /// ```ignore
    /// use arcature::prelude::*;
    /// use arcature_test::TestApp;
    ///
    /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
    /// let router = Application::new()
    ///     .routes(Routes::new().route("/", get(|| async { "ok" })))
    ///     .build()
    ///     .into_router();
    /// let app = TestApp::new(router).await?;
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// The pre-routing layers (application proxy, request-id) are **not**
    /// applied — see the module documentation for the rationale and the
    /// alternatives for testing proxy behaviour.
    ///
    /// Construction is deterministic and performs no I/O: subsystem resources
    /// (database, cache, mail, storage, jobs) are connected only by
    /// `run_with_lifecycle`, never by `into_router`. A test therefore builds
    /// an `Application` with exactly the routes and layers it wants and pays
    /// no cost for unrelated subsystems.
    pub fn into_router(self) -> crate::axum::Router<()> {
        assemble_router(self).0
    }
}