@@ -27,7 +27,7 @@ User JSON → [Config DTOs] → validate/transform → [Domain Types]
2727| ** Layer** | Application | Domain |
2828| ** Purpose** | JSON parsing | Business logic |
2929| ** Types** | Raw primitives (` String ` , ` u32 ` ) | Validated newtypes (` NonZeroU32 ` , ` ProfileName ` ) |
30- | ** Validation** | Deferred to ` to_*_config() ` | Enforced at construction |
30+ | ** Validation** | Deferred to ` TryFrom ` conversion | Enforced at construction |
3131| ** Serde** | Heavy (` Deserialize ` , ` Serialize ` , ` JsonSchema ` ) | Minimal |
3232
3333## Module Structure
@@ -53,18 +53,24 @@ config/
5353
5454## Conversion Pattern
5555
56- Each DTO provides a ` to_*_config() ` method that validates and converts to domain types:
56+ Each DTO implements ` TryFrom ` for idiomatic Rust conversion to domain types.
57+ This follows the pattern documented in ` docs/decisions/tryfrom-for-dto-to-domain-conversion.md ` .
5758
5859``` rust
5960// Example: PrometheusSection → PrometheusConfig
60- impl PrometheusSection {
61- pub fn to_prometheus_config (& self ) -> Result <PrometheusConfig , CreateConfigError > {
61+ impl TryFrom <PrometheusSection > for PrometheusConfig {
62+ type Error = CreateConfigError ;
63+
64+ fn try_from (section : PrometheusSection ) -> Result <Self , Self :: Error > {
6265 // Validates: scrape_interval must be > 0
63- let interval = NonZeroU32 :: new (self . scrape_interval_in_secs)
66+ let interval = NonZeroU32 :: new (section . scrape_interval_in_secs)
6467 . ok_or_else (|| CreateConfigError :: InvalidPrometheusConfig (... ))? ;
6568 Ok (PrometheusConfig :: new (interval ))
6669 }
6770}
71+
72+ // Usage:
73+ let config : PrometheusConfig = section . try_into ()? ;
6874```
6975
7076## Constraints Expressed in Rust (Not in JSON Schema)
@@ -77,7 +83,7 @@ The Rust types express constraints that JSON Schema cannot fully capture:
7783| Mutually exclusive options | Tagged enums with ` #[serde(tag = "...")] ` | ` oneOf ` is complex and error-prone |
7884| Path validation | ` PathBuf ` with existence checks | No file system awareness |
7985| Format validation | Newtype constructors (` ProfileName::new() ` ) | Regex patterns are limited |
80- | Cross-field validation | Custom ` to_*_config() ` logic | No support |
86+ | Cross-field validation | Custom ` TryFrom ` implementation logic | No support |
8187| Secret handling | ` Password ` , ` ApiToken ` wrappers | No security semantics |
8288
8389## For AI Agents
@@ -86,7 +92,7 @@ When generating environment configuration:
8692
87931 . ** Reference these Rust types** for accurate constraint information
88942 . ** Follow the structure** in ` EnvironmentCreationConfig ` as the root type
89- 3 . ** Check validation logic** in ` to_*_config() ` methods for business rules
95+ 3 . ** Check validation logic** in ` TryFrom ` implementations for business rules
90964 . ** Use JSON schema** (` schemas/environment-config.json ` ) for basic structure, but trust Rust types for constraints
9197
9298## Related Documentation
0 commit comments