Skip to main content

Module schema

Module schema 

Source
Available on crate feature schema only.
Expand description

A JSON Schema for the files this program reads.

schemars describes a struct. What an editor needs is a description of the file, and the two are not the same thing here: a config file is a map of sections, and a struct is one section. This module is the difference — wrapping a struct’s schema under its section key, marking the fields #[config(secret)] covers, and merging several structs into the one file they share.

Opt in with the schema argument, which is what emits schema(). Like save, it is a separate argument rather than something every type gets, because the method needs a trait — JsonSchema — that the user has to derive.

use schemars::JsonSchema;
use serde::Deserialize;

#[dynamic_config::dynamic_config(files = ["config.json"], key = "db", schema)]
#[derive(Deserialize, JsonSchema)]
struct DbConfig {
    host: String,
    #[config(secret)]
    password: String,
}

let schema = DbConfig::schema();

// A file-level schema: `{"db": {...}}`, not `{...}`.
assert!(schema["properties"]["db"].is_object());
// And the secret is marked as one.
assert_eq!(
    schema["properties"]["db"]["properties"]["password"]["writeOnly"],
    true
);

§Wiring it up

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

The JSON case is the reason $schema is the one top-level key this crate does not treat as a section. The other two are comments, and were never a problem.

§What is deliberately not in the schema

Nothing is required, at any depth. schemars marks every field that is neither Option nor #[serde(default)] as required, which 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 none of them are visible to an editor. Left in place it would light up every 12-factor deployment’s config file in red for values that are perfectly well supplied. check() answers the question a schema cannot — does this actually resolve — with every layer in view.

The top level accepts unknown keys. Other sections belong to other structs, and one struct’s schema has no business calling them a mistake. Use merge to describe the whole file, and unknown-key detection — check() — for the part a schema cannot see.

Functions§

merge
Combines several section schemas into one schema for the file they share.
section
Wraps one struct’s schema as the section it occupies in a file.