Defaults and Optionality
Validation Rules provide two distinct mechanisms for handling missing elements in a parsed configuration document:
Defaults — supply a predefined value when a scalar value or value list is missing.
Optionality — explicitly mark a node as optional so it may be omitted entirely, along with all of its child nodes.
While both mechanisms address missing data, they serve different purposes and have different semantics.
Feature |
Defaults |
Optionality |
|---|---|---|
Applies to |
Any node (values, lists, sections) |
|
Purpose |
Supply a predefined value if the node is missing |
Allow the node (and its children) to be omitted entirely |
Child Nodes |
Defaults affect only the node itself |
Optionality cascades to all child nodes |
Constraints |
Default values bypass constraints (except |
Constraints apply only if the node exists |
Interaction |
Must not be combined with |
Must not be combined with |
Common Use |
Avoid repetitive program logic for common values |
Support optional features or configuration sections |
[api.host]
type: "text"
default: "127.0.0.1"
[api.port]
type: "integer"
default: 9000
[client]
type: "section"
is_optional: yes
[client.name]
type: "text"
[api] # The "api" section is required
# "host" and "port" use their default values
# The "client" section is optional
Design Rationale
Defaults are intentionally limited to scalar values and value lists to keep their behavior simple, predictable, and easy to implement.
While it might appear useful to provide defaults for entire sections or complete configurations, doing so would blur the boundary between validation and configuration derivation. Applications that require a default configuration should provide one explicitly (for example, by shipping a base configuration file or embedding defaults in code) and then validate user-provided overrides.
Defaults in Validation Rules are therefore designed as a lightweight, node-level convenience. They eliminate repetitive application logic while also serving as machine-readable documentation of commonly used values.
Rules for Defaults
Default Field: A node-rules definition may specify a
defaultvalue that is used if the node is missing from the configuration document.[api.host] type: "text" default: "127.0.0.1"
Allowed Node Types: Defaults may only be defined for scalar values and value lists.
[article.tags] type: "ValueList" default: "article", "news" [article.tags.vr_entry] type: "text" minimum: 1 maximum: 60
Type Matching: A default value must match the declared
typeof the node-rules definition.[api.port] type: "integer" default: 9000
Constraints Ignored: Default values are not validated against local constraints, except for the
typeconstraint.This allows placeholder or empty values to be supplied even if they would not be valid as explicit user input.
[server.name] type: "text" minimum: 1 default: "" # Allowed, even though the minimum length is 1
No Combination with Optionality: A node-rules definition must not combine
defaultwithis_optional.Validators must report this as an error.
[server.name] type: "text" is_optional: yes default: "example" # ERROR: default and is_optional must not be combined
Rules for Optional Nodes
Optional Flag: Any node may be marked as optional by setting
is_optional: yes.[client] type: "section" is_optional: yes [client.name] type: "text"
Optionality Includes Child Nodes: If an optional node does not exist, none of its child nodes may exist either.
Even if child nodes are normally required, they are only validated if the parent node itself exists.
# An empty document is valid because "client" is optionalNo Defaults for Missing Optional Nodes: Defaults are not applied when an optional node is missing.
Child nodes are neither created nor validated unless the optional parent node exists.
[client] type: "section" is_optional: yes [client.name] type: "text" default: "unknown"
# Empty document — "client" does not exist, # so "client.name" is not created.
[client] # "client" exists, so "client.name" is created # with the default value "unknown"