Skip to main content

modo/extractor/
service.rs

1use std::sync::Arc;
2
3use axum::extract::{FromRef, FromRequestParts};
4use http::request::Parts;
5
6use crate::service::AppState;
7
8/// Axum extractor that retrieves a service `T` from the application's service registry.
9///
10/// The inner value is an `Arc<T>`, so cloning the extractor is cheap.
11/// Returns a 500 Internal Server Error if `T` was not registered before the server started.
12///
13/// # Example
14///
15/// ```
16/// use modo::Service;
17///
18/// struct MyService;
19///
20/// async fn handler(Service(svc): Service<MyService>) {
21///     // svc is Arc<MyService>
22/// }
23/// ```
24pub struct Service<T>(pub Arc<T>);
25
26impl<S, T> FromRequestParts<S> for Service<T>
27where
28    S: Send + Sync,
29    T: Send + Sync + 'static,
30    AppState: FromRef<S>,
31{
32    type Rejection = crate::error::Error;
33
34    async fn from_request_parts(_parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
35        let app_state = AppState::from_ref(state);
36
37        app_state.get::<T>().map(Service).ok_or_else(|| {
38            crate::error::Error::internal(format!(
39                "service not found in registry: {}",
40                std::any::type_name::<T>()
41            ))
42        })
43    }
44}