Application context
App context
App context shares values across requests. Register a value on the router, then borrow it with app_context(cx) wherever you have a request context. A database pool is a typical app context value.
Values are identified by their Rust type. The router accepts one value of each type.
Registering values
Build the router and chain .app_context(value) for every value you want to share:
use hearth::router::{Router, RouterBuilderDiscoverExt, module_router};
pub fn router() -> Router {
module_router!()
.discover()
.app_context(Database::connect())
.app_context(HttpClient::new())
.build()
}
Registering two values of the same type panics. Wrap them in distinct types when you need to share both:
use hearth::router::module_router;
struct PrimaryDb(Database);
struct ReplicaDb(Database);
module_router!()
.app_context(PrimaryDb(Database::connect_primary()))
.app_context(ReplicaDb(Database::connect_replica()))
.build();
Reading values
Inside any handler that has access to a Cx, call app_context::<T>(cx) to borrow the registered value:
use hearth::{
context::{Cx, app_context},
Result,
router::page,
view::{View, view},
};
#[page]
async fn user_profile(cx: &Cx) -> Result<impl View> {
let db: &Database = app_context(cx);
let user = db.fetch_user(42).await;
Ok(view! { <h1>"Hello, " (user.name) </h1> })
}
The requested type must exactly match the registered type. app_context panics if that type was not registered.
When an app context value is intentionally optional, use try_app_context::<T>(cx) instead. It returns None when the type was not registered:
use hearth::context::{Cx, try_app_context};
fn feature_config(cx: &Cx) -> Option<&FeatureConfig> {
try_app_context(cx)
}
Requirements
The value must implement Any + Send + Sync. The Any bound requires it to be 'static, so it cannot borrow temporary data.
Requests borrow the registered value. The value does not need to implement Clone.