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 — 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 — but no code path inside rtb-config
ever returns it.