API improvements
- Added public `Error`, `Result`, `InitFuture`, and `ShutdownFuture` aliases. - Added `TypeMapState` as the default state instead of `Arc<TypeMap>`. - Added `App::route`, `App::mount`, and `App::store`. - Changed `App::init()` to return `InitializedApp<S>`. - Added `InitializedApp::router()`, `state()`, `into_parts()`, and `shutdown()`. - Made shutdown hooks fallible: `Result<()>`. - Made `AdHocPlugin::on_shutdown` accept capturing closures. - Added `Default` for `App` and `AdHocPlugin`. Improved AppState macro: - Uses `axum_app_wrapper::Error`. - Supports generic state structs. - Fixed the stale `Arc<AppState>` doc snippet.
This commit is contained in:
30
README.md
30
README.md
@@ -17,12 +17,32 @@ This crate is intentionally thin. It does not replace axum's router, extractors,
|
||||
1. `on_init` in registration order, passing a `TypeMap` to build state.
|
||||
2. `S::try_from(TypeMap)` to build the final typed app state.
|
||||
3. `on_setup` in registration order, passing `Router<S>` and `&S`.
|
||||
4. `on_shutdown` consecutively in reverse registration order: the last registered plugin shuts down first, and each hook finishes before the next one starts.
|
||||
4. `InitializedApp::shutdown()` runs `on_shutdown` consecutively in reverse registration order: the last registered plugin shuts down first, and each hook finishes before the next one starts.
|
||||
|
||||
|
||||
## Example
|
||||
See the `examples` folder for full examples.
|
||||
|
||||
`App::init()` returns an initialized app handle. Use `router()` to get a ready-to-serve `Router<()>`, `state()` to inspect the finalized state, and `shutdown()` from your graceful shutdown path:
|
||||
|
||||
```rust
|
||||
let app = App::<AppState>::new()
|
||||
.store(config)
|
||||
.route("/health", axum::routing::get(health))
|
||||
.register(metrics_plugin)
|
||||
.init()
|
||||
.await?;
|
||||
|
||||
let router = app.router();
|
||||
let service_name = &app.state().config.service_name;
|
||||
|
||||
axum::serve(listener, router)
|
||||
.with_graceful_shutdown(async move {
|
||||
tokio::signal::ctrl_c().await.expect("failed to listen for ctrl-c");
|
||||
app.shutdown().await.expect("failed to shut down");
|
||||
})
|
||||
.await?;
|
||||
```
|
||||
|
||||
For `on_setup` closures that access typed state, construct the plugin as
|
||||
`AdHocPlugin::<AppState>::new()`. That gives Rust enough context to infer the `state` parameter:
|
||||
@@ -41,15 +61,15 @@ Implement `AppPlugin<S>` directly when setup should be reusable across apps:
|
||||
|
||||
```rust
|
||||
use axum::Router;
|
||||
use axum_app_wrapper::{AppPlugin, TypeMap};
|
||||
use futures::{future::BoxFuture, FutureExt};
|
||||
use axum_app_wrapper::{AppPlugin, InitFuture, Result, TypeMap};
|
||||
use futures::FutureExt;
|
||||
|
||||
struct ConfigPlugin {
|
||||
config: Config,
|
||||
}
|
||||
|
||||
impl AppPlugin<AppState> for ConfigPlugin {
|
||||
fn on_init(&mut self, mut state: TypeMap) -> BoxFuture<'static, anyhow::Result<TypeMap>> {
|
||||
fn on_init(&mut self, mut state: TypeMap) -> InitFuture {
|
||||
let config = self.config.clone();
|
||||
async move {
|
||||
state.insert(config);
|
||||
@@ -62,7 +82,7 @@ impl AppPlugin<AppState> for ConfigPlugin {
|
||||
&mut self,
|
||||
router: Router<AppState>,
|
||||
_state: &AppState,
|
||||
) -> anyhow::Result<Router<AppState>> {
|
||||
) -> Result<Router<AppState>> {
|
||||
Ok(router.route("/health", axum::routing::get(health)))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user