Skip to main content

rustapi_core/app/
health.rs

1use super::production::ProductionDefaultsConfig;
2use super::types::RustApi;
3
4impl RustApi {
5    /// Enable automatic status page with default configuration
6    pub fn status_page(self) -> Self {
7        self.status_page_with_config(crate::status::StatusConfig::default())
8    }
9
10    /// Enable automatic status page with custom configuration
11    pub fn status_page_with_config(mut self, config: crate::status::StatusConfig) -> Self {
12        self.status_config = Some(config);
13        self
14    }
15
16    /// Enable built-in `/health`, `/ready`, and `/live` endpoints with default paths.
17    ///
18    /// The default health check includes a lightweight `self` probe so the
19    /// endpoints are immediately useful even before dependency checks are added.
20    pub fn health_endpoints(mut self) -> Self {
21        self.health_endpoint_config = Some(crate::health::HealthEndpointConfig::default());
22        if self.health_check.is_none() {
23            self.health_check = Some(crate::health::HealthCheckBuilder::default().build());
24        }
25        self
26    }
27
28    /// Enable built-in health endpoints with custom paths.
29    pub fn health_endpoints_with_config(
30        mut self,
31        config: crate::health::HealthEndpointConfig,
32    ) -> Self {
33        self.health_endpoint_config = Some(config);
34        if self.health_check.is_none() {
35            self.health_check = Some(crate::health::HealthCheckBuilder::default().build());
36        }
37        self
38    }
39
40    /// Register a custom health check and enable built-in health endpoints.
41    ///
42    /// The configured check is used by `/health` and `/ready`, while `/live`
43    /// remains a lightweight process-level probe.
44    pub fn with_health_check(mut self, health_check: crate::health::HealthCheck) -> Self {
45        self.health_check = Some(health_check);
46        if self.health_endpoint_config.is_none() {
47            self.health_endpoint_config = Some(crate::health::HealthEndpointConfig::default());
48        }
49        self
50    }
51
52    /// Apply a one-call production baseline preset.
53    ///
54    /// This enables:
55    /// - `RequestIdLayer`
56    /// - `TracingLayer` with `service` and `environment` fields
57    /// - built-in `/health`, `/ready`, and `/live` probes
58    pub fn production_defaults(self, service_name: impl Into<String>) -> Self {
59        self.production_defaults_with_config(ProductionDefaultsConfig::new(service_name))
60    }
61
62    /// Apply the production baseline preset with custom configuration.
63    pub fn production_defaults_with_config(mut self, config: ProductionDefaultsConfig) -> Self {
64        if config.enable_request_id {
65            self = self.layer(crate::middleware::RequestIdLayer::new());
66        }
67
68        if config.enable_tracing {
69            let mut tracing_layer =
70                crate::middleware::TracingLayer::with_level(config.tracing_level)
71                    .with_field("service", config.service_name.clone())
72                    .with_field("environment", crate::error::get_environment().to_string());
73
74            if let Some(version) = &config.version {
75                tracing_layer = tracing_layer.with_field("version", version.clone());
76            }
77
78            self = self.layer(tracing_layer);
79        }
80
81        if config.enable_health_endpoints {
82            if self.health_check.is_none() {
83                let mut builder = crate::health::HealthCheckBuilder::default();
84                if let Some(version) = &config.version {
85                    builder = builder.version(version.clone());
86                }
87                self.health_check = Some(builder.build());
88            }
89
90            if self.health_endpoint_config.is_none() {
91                self.health_endpoint_config =
92                    Some(config.health_endpoint_config.unwrap_or_default());
93            }
94        }
95
96        self
97    }
98    pub(super) fn apply_health_endpoints(&mut self) {
99        if let Some(config) = &self.health_endpoint_config {
100            use crate::router::get;
101
102            let health_check = self
103                .health_check
104                .clone()
105                .unwrap_or_else(|| crate::health::HealthCheckBuilder::default().build());
106
107            let health_path = config.health_path.clone();
108            let readiness_path = config.readiness_path.clone();
109            let liveness_path = config.liveness_path.clone();
110
111            let health_handler = {
112                let health_check = health_check.clone();
113                move || {
114                    let health_check = health_check.clone();
115                    async move { crate::health::health_response(health_check).await }
116                }
117            };
118
119            let readiness_handler = {
120                let health_check = health_check.clone();
121                move || {
122                    let health_check = health_check.clone();
123                    async move { crate::health::readiness_response(health_check).await }
124                }
125            };
126
127            let liveness_handler = || async { crate::health::liveness_response().await };
128
129            let router = std::mem::take(&mut self.router);
130            self.router = router
131                .route(&health_path, get(health_handler))
132                .route(&readiness_path, get(readiness_handler))
133                .route(&liveness_path, get(liveness_handler));
134        }
135    }
136}