Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Schema

The schema attribute

#![allow(unused)]
fn main() {
#[dynamic_config(files = ["config.json"], key = "db", schema)]
#[derive(Deserialize, JsonSchema)]
}

Generates schema(). Requires the schema feature and Self: JsonSchema — opt-in for the same reason save is: the method needs a trait you have to derive, and a where Self: JsonSchema clause cannot express that (rustc rejects an inherent method whose bound a concrete Self does not meet, at the definition rather than at the call).

A schema for the config files

With the schema feature, every config type can describe the file it reads, so an editor completes and validates it:

#![allow(unused)]
fn main() {
#[dynamic_config(files = ["config.json"], key = "db", schema)]
#[derive(Deserialize, JsonSchema)]
struct DbConfig {
    /// Where the database lives.        <- becomes the hover text
    host: String,
    #[config(secret)]                    <- becomes `writeOnly: true`
    password: String,
}

let schema = DbConfig::schema();

// Several types over one file describe that one file together.
let whole = dynamic_config::schema::merge([DbConfig::schema(), ServerConfig::schema()]);
}

What comes out describes the file, not the struct — the struct is one section, and a config file is a map of them, so the schema is the struct's wrapped under its key.

FormatHow the editor finds it
JSON"$schema": "./config.schema.json" as a top-level key
YAML# yaml-language-server: $schema=./config.schema.json
TOML#:schema ./config.schema.json

The JSON row is why $schema is the one top-level key this crate does not read as a section: otherwise wiring the schema into the file it describes would stop the file from loading.

Nothing is marked required, and that is the point

schemars marks every field that is neither Option nor #[serde(default)] as required. That is right for a struct and wrong for a config file: the environment, a flag, an override or a computed default can all supply a value, and an editor sees none of them. Left in place it would light up every 12-factor config file in red for values that are perfectly well supplied — so the emitted schema drops required at every depth.

The question a schema cannot answer — does this actually resolve — is what check() is for, with every layer in view.