Skip to main content

nova_boot/
state.rs

1use axum::{
2    extract::FromRequestParts,
3    http::StatusCode,
4    http::request::Parts,
5    response::{IntoResponse, Response},
6};
7use std::fmt;
8
9/// Wrapper extractor for application state.
10///
11/// Use this extractor in handlers to obtain a cloned instance of the
12/// application state type previously injected into the Axum router via
13/// `axum::Extension(state)` (NovaApp injects the state for you).
14///
15/// Example:
16///
17/// ```ignore
18/// async fn handler(state: NovaState<MyState>) -> impl IntoResponse {
19///     let s: MyState = state.0; // cloned state
20///     // ...
21/// }
22/// ```
23#[derive(Debug, Clone)]
24pub struct NovaState<S>(pub S);
25
26impl<S, State> FromRequestParts<State> for NovaState<S>
27where
28    S: Clone + Send + Sync + 'static,
29    State: Send + Sync,
30{
31    type Rejection = NovaStateRejection;
32
33    fn from_request_parts(
34        parts: &mut Parts,
35        _state: &State,
36    ) -> impl std::future::Future<Output = Result<Self, Self::Rejection>> + Send {
37        let result = parts
38            .extensions
39            .get::<S>()
40            .cloned()
41            .map(NovaState)
42            .ok_or(NovaStateRejection);
43
44        async move { result }
45    }
46}
47
48/// Error returned when application state is missing from request extensions.
49///
50/// This occurs when the application failed to add `Extension<...>` for the
51/// configured state type. The rejection implements `IntoResponse` and will
52/// produce a 500-level response when returned from an extractor.
53#[derive(Debug)]
54pub struct NovaStateRejection;
55
56impl fmt::Display for NovaStateRejection {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        write!(
59            f,
60            "Application state is not present in request extensions. \
61                   Ensure you added the state via `NovaApp::new()` and did not remove the `Extension` layer."
62        )
63    }
64}
65
66impl std::error::Error for NovaStateRejection {}
67
68impl IntoResponse for NovaStateRejection {
69    fn into_response(self) -> Response {
70        (
71            StatusCode::INTERNAL_SERVER_ERROR,
72            "Internal server error: application state missing",
73        )
74            .into_response()
75    }
76}