Axum State

Axum allows providing a "state" struct to the Router. Roadster provides its state (DB connection pool, etc) in the AppContext struct, which can be used either as the Axum state directly. Or, if non-Roadster state is needed for some resource not provided by Roadster, a custom struct can be used as long as it implements FromRef so Roadster can get its AppContext state from Axum.

FromRef for custom state

FromRef can either be derived

#[derive(Clone, FromRef)]
pub struct CustomState {
    pub context: AppContext,
    pub custom_field: String,
}

or implemented manually

#[derive(Clone)]
pub struct CustomState {
    pub context: AppContext,
    pub custom_field: String,
}

impl FromRef<CustomState> for AppContext {
    fn from_ref(input: &CustomState) -> Self {
        input.context.clone()
    }
}

Providing state

The app state needs to be provided to the HttpService when it's created. If the HttpServiceBuilder is used to register the service with the ServiceRegistry#register_builder method, the state will be provided automatically when the ServiceRegistry builds the service.

use roadster::app::context::AppContext;
use roadster::service::http::service::HttpService;

type App = RoadsterApp<AppContext>;

fn build_app() -> App {
    RoadsterApp::builder()
        // Use the default `AppContext` for this example
        .state_provider(|context| Ok(context))
        .add_service_provider(move |registry, state| {
            Box::pin(async move {
                registry
                    .register_builder(HttpService::builder(Some("/api"), state))
                    .await?;
                Ok(())
            })
        })
        .build()
}

See also