Browse documentation
Documentation

Application context

Edit this guide on GitHub

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.