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