Write config back and export a schema¶
The mutable feature adds two associated items to Config<C>: write, which puts
the current value on disk, and schema, which emits a JSON Schema for the config
struct. They exist to back config set, config schema and config validate style
subcommands.
Enable the feature and the derives¶
Both items need more from C than the rest of the crate does:
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Deserialize, Serialize, JsonSchema)]
struct MyConfig {
host: String,
port: u16,
}
Without Serialize and JsonSchema the methods are not callable and the compiler
says the method `write` exists for struct `Config<MyConfig>`, but its trait bounds
were not satisfied, with a note naming Serialize and JsonSchema as the
unsatisfied bounds. The fix is usually a missing derive.
Write the current configuration to a file¶
Missing parent directories are created. The format follows the extension:
| Extension | Format |
|---|---|
.yml, .yaml |
YAML |
.toml |
TOML |
.json |
JSON |
| anything else, or none | YAML |
Write YAML or JSON if you intend to read the file back. ConfigBuilder::user_file
parses every file as YAML, so a .toml file this method wrote cannot be loaded again
by this crate.
Understand what gets written¶
write serialises the merged value, exactly what get() returns, not the
file layer on its own. Three consequences to design around:
- Environment overrides are baked in. If
MYTOOL_PORT=9999is set when you callwrite,port: 9999is now in the file permanently, as if a human had typed it. - Embedded defaults become explicit. Every key gets written out, so a later release that changes a default no longer affects this user.
- The existing file is replaced. Comments, key order and any hand-formatting in the user's file are gone.
For a config set command that edits one key, this is usually the wrong tool: it
turns a one-key edit into a full rewrite of everything the process happened to be
running with. Editing the user's file directly keeps the rest of it intact.
The write is also not atomic: a crash part-way leaves a truncated file. If that matters, serialise to a temporary file in the same directory and rename it into place.
Emit a JSON Schema for the config struct¶
schema() is an associated function, so it needs no loaded config and can run before
anything is read. The result is a serde_json::Value with the usual top-level keys
($schema, title, type and properties), generated fresh on each call. There is
no caching; the call is cheap enough for CLI use.
This is what to wire to a config schema subcommand, and what to hand to an editor
for YAML completion against your tool's config file.
Validate a value before writing it¶
Nothing in the crate does this for you. schema() produces the schema; validating a
candidate value against it is the caller's job, using a JSON Schema validator of your
choice.
ConfigError::Schema exists for exactly that step, so a validation failure in your
own code has a home in the same error type. No code path inside rtb-config ever
returns it.