Skip to main content

rskit_config/
app.rs

1//! Service-application config convenience trait.
2
3use crate::ServiceConfig;
4
5/// Trait that every application config struct must implement.
6///
7/// Typically implemented by a struct that embeds [`ServiceConfig`] and adds
8/// service-specific fields.
9///
10/// ```no_run
11/// use rskit_config::{AppConfig, ConfigLoader, SecretString, ServiceConfig};
12/// use rskit_validation::Validate;
13///
14/// #[derive(serde::Deserialize)]
15/// struct MyConfig {
16///     #[serde(flatten)]
17///     service: ServiceConfig,
18///     grpc_port: u16,
19///     api_token: SecretString,
20/// }
21///
22/// impl Validate for MyConfig {
23///     fn validate(&self) -> Result<(), validator::ValidationErrors> {
24///         self.service.validate()?;
25///         if self.grpc_port == 0 {
26///             let mut errors = validator::ValidationErrors::new();
27///             errors.add("grpc_port", validator::ValidationError::new("range"));
28///             return Err(errors);
29///         }
30///         Ok(())
31///     }
32/// }
33///
34/// impl AppConfig for MyConfig {
35///     fn apply_defaults(&mut self) {
36///         if self.grpc_port == 0 { self.grpc_port = 50051; }
37///     }
38///     fn service_config(&self) -> &ServiceConfig { &self.service }
39/// }
40///
41/// # fn main() -> rskit_errors::AppResult<()> {
42/// let cfg: MyConfig = ConfigLoader::app().load_app()?;
43/// assert_eq!(cfg.api_token.to_string(), "***");
44/// # Ok(())
45/// # }
46/// ```
47pub trait AppConfig:
48    serde::de::DeserializeOwned + rskit_validation::Validate + Send + Sync + 'static
49{
50    /// Apply any programmatic defaults after deserialization.
51    fn apply_defaults(&mut self);
52    /// Return a reference to the embedded [`ServiceConfig`].
53    fn service_config(&self) -> &ServiceConfig;
54}