aro_web/lib.rs
1//! HTTP/ADR layer for the Aro web framework.
2//!
3//! This crate provides the web adapter built on Axum. Axum is re-exported at
4//! the crate root as an intentional escape hatch: advanced features (auth,
5//! `WebSockets`, `OpenAPI`, static files, etc.) are delegated to the Axum/tower
6//! ecosystem rather than wrapped by Aro.
7
8mod app;
9pub mod cache;
10pub mod config;
11pub mod dep;
12pub mod error;
13pub mod fallback;
14pub mod health;
15pub mod json_body;
16pub mod middleware;
17pub mod state;
18
19#[cfg(any(test, feature = "test-utils"))]
20pub mod test;
21
22pub use app::App;
23pub use axum;
24pub use axum::extract::DefaultBodyLimit;
25
26#[doc(hidden)]
27pub use ::pastey as __private_pastey;
28
29// SSE support
30pub use axum::response::sse::{Event, KeepAlive, Sse};
31
32/// Collect route handlers into an `axum::Router<AroState>`.
33///
34/// Takes a list of handler function names and chains their generated
35/// `__aro_register_<fn>` functions into a single Router. Non-empty invocations
36/// produce a `Router<AroState>`, making handlers compatible with both stateless
37/// handlers and handlers using `Dep<T>` extractors.
38///
39/// # Examples
40///
41/// ```ignore
42/// use aro_web::routes;
43///
44/// // Stateless handlers
45/// let router = routes![hello, get_user, create_user];
46/// App::new().routes_with_state(router).build();
47///
48/// // Stateful handlers using Dep<T>
49/// let router = routes![handler_with_dep, stateless_handler];
50/// App::new()
51/// .register::<dyn MyService>(service)
52/// .routes_with_state(router)
53/// .build();
54/// ```
55///
56/// Module-qualified paths are supported:
57///
58/// ```ignore
59/// let router = routes![users::get_user, users::create_user];
60/// ```
61///
62/// An empty invocation returns an empty `Router<()>` for composition with
63/// stateless routes; use [`App::routes_with_state`](App::routes_with_state) only
64/// when the router contains handlers:
65///
66/// ```ignore
67/// let router = routes![];
68/// ```
69#[macro_export]
70macro_rules! routes {
71 () => {
72 $crate::axum::Router::new()
73 };
74 ($($($segment:ident)::+),+ $(,)?) => {
75 $crate::__private_pastey::paste! {{
76 let router = $crate::axum::Router::new();
77 $(
78 let router = $crate::__aro_route_register!(router [] $($segment)::+);
79 )+
80 router
81 }}
82 };
83}
84
85/// Internal helper: resolve a handler path to its registration function and call it.
86///
87/// Uses brackets `[prefix segments]` as an accumulator for the module path.
88#[doc(hidden)]
89#[macro_export]
90macro_rules! __aro_route_register {
91 // Peel off a leading module segment, push it into the accumulator.
92 ($router:ident [$($prefix:tt)*] $first:ident :: $($rest:ident)::+) => {
93 $crate::__aro_route_register!($router [$($prefix)* $first ::] $($rest)::+)
94 };
95 // Base case: single ident remaining is the handler name.
96 ($router:ident [$($prefix:tt)*] $handler:ident) => {
97 $crate::__private_pastey::paste! { $($prefix)* [<__aro_register_ $handler>]($router) }
98 };
99}