modo/flash/mod.rs
1//! # modo::flash
2//!
3//! Cookie-based flash messages for one-time cross-request notifications.
4//!
5//! Provides:
6//!
7//! - [`FlashLayer`] — Tower [`Layer`](tower::Layer) that enables flash cookie support on a router.
8//! - [`FlashMiddleware`] — Tower [`Service`](tower::Service) produced by [`FlashLayer`].
9//! - [`Flash`] — axum extractor for writing and reading flash messages in handlers.
10//! - [`FlashEntry`] — a single message carrying a severity `level` and `message` text.
11//!
12//! Flash messages are stored in a signed cookie and cleared after being read.
13//! They survive exactly one redirect: the current request writes a message and
14//! the next request reads it. Once read, the cookie is removed from the response.
15//!
16//! Requires [`FlashLayer`] to be applied to the router before using the [`Flash`] extractor.
17//!
18//! When the `template` module's `TemplateContextLayer` is also applied, a
19//! `flash_messages()` callable is automatically injected into every MiniJinja
20//! template context. Calling it from a template is equivalent to calling
21//! [`Flash::messages`] from a handler — it marks the messages as consumed and
22//! clears the cookie on the response.
23//!
24//! ## Quick start
25//!
26//! ```rust,ignore
27//! use modo::cookie::{CookieConfig, key_from_config};
28//! use modo::flash::{Flash, FlashLayer};
29//! use axum::{Router, routing::{get, post}, response::Redirect};
30//!
31//! // Build the layer from your cookie config
32//! let config: CookieConfig = app_config.cookie.clone();
33//! let key = key_from_config(&config).unwrap();
34//!
35//! let app = Router::new()
36//! .route("/form", post(submit_handler))
37//! .route("/result", get(result_handler))
38//! .layer(FlashLayer::new(&config, &key));
39//!
40//! // Write a flash message and redirect
41//! async fn submit_handler(flash: Flash) -> Redirect {
42//! flash.success("Record saved.");
43//! Redirect::to("/result")
44//! }
45//!
46//! // Read flash messages on the next request
47//! async fn result_handler(flash: Flash) -> String {
48//! let msgs = flash.messages();
49//! msgs.iter()
50//! .map(|m| format!("[{}] {}", m.level, m.message))
51//! .collect::<Vec<_>>()
52//! .join("\n")
53//! }
54//! ```
55
56mod extractor;
57mod middleware;
58pub(crate) mod state;
59
60pub use extractor::Flash;
61pub use middleware::{FlashLayer, FlashMiddleware};
62pub use state::FlashEntry;