use dynamic_config::dynamic_config;
use schemars::JsonSchema;
use serde::Deserialize;
#[dynamic_config(files = ["dynamic-config/examples/app.json"], key = "db", schema)]
#[derive(Deserialize, JsonSchema)]
struct DbConfig {
#[allow(dead_code)]
host: String,
#[config(secret)]
#[serde(default)]
#[allow(dead_code)]
password: String,
}
#[dynamic_config(files = ["dynamic-config/examples/app.json"], key = "server", schema)]
#[derive(Deserialize, JsonSchema)]
struct ServerConfig {
host: String,
port: u16,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let server = ServerConfig::load()?;
println!("loaded: {}:{}\n", server.host, server.port);
let db = DbConfig::schema();
println!("DbConfig::schema() describes a file:");
println!(" top-level type = {}", db["type"]);
println!(" its only section = db");
println!(
" password writeOnly = {}",
db["properties"]["db"]["properties"]["password"]["writeOnly"]
);
println!(
" host writeOnly = {} (only the marked fields)",
db["properties"]["db"]["properties"]["host"]
.get("writeOnly")
.map_or("absent", |_| "true")
);
let whole_file = dynamic_config::schema::merge([DbConfig::schema(), ServerConfig::schema()]);
println!("\nmerged, both sections are there:");
for section in whole_file["properties"]
.as_object()
.expect("the merged schema has properties")
.keys()
{
println!(" {section}");
}
println!(
"\nrequired inside the db section = {:?}",
whole_file["properties"]["db"].get("required")
);
println!(
"required inside db.pool = {:?}",
whole_file["properties"]["db"]["properties"]
.get("pool")
.and_then(|pool| pool.get("required"))
);
println!(
"A field the file omits may still be supplied by the environment, a\n\
flag or a computed default — none of which an editor can see. Marking\n\
fields required would light up every 12-factor config file in red."
);
let path = std::env::temp_dir().join("dynamic-config-example.schema.json");
std::fs::write(&path, serde_json::to_string_pretty(&whole_file)?)?;
println!("\nwrote {}", path.display());
println!(
"\nWire it up per format:\n\
\x20 JSON \"$schema\": \"./app.schema.json\" (a top-level key)\n\
\x20 YAML # yaml-language-server: $schema=./app.schema.json\n\
\x20 TOML #:schema ./app.schema.json"
);
println!(
"\n`$schema` is the one top-level key this crate does not read as a\n\
section — otherwise wiring the schema into the file it describes would\n\
stop the file from loading."
);
std::fs::remove_file(&path)?;
Ok(())
}