A TOML Schema is a set of TOML-based constructs that define the structure, the names, and the types of configuration data on a TOML file.
The TOML Schema is used to validate the input of a TOML file during parsing to:
The schema format follows the TOML specification, meaning that a TOML Schema is in itself a valid TOML document.
[toml-schema]
[elements]
[types]
<simple-type>
min
and max
minlength
and maxlength
any
optional
pattern
Let's look at the TOML example displayed on the front page of toml.io:
# This is a TOML document
title = "TOML Example"
[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00
[database]
enabled = true
ports = [ 8000, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }
[servers]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend"
[servers.beta]
ip = "10.0.0.2"
role = "backend"
Example of a TOML Schema that validates the TOML document above:
# This is a TOML Schema document
[toml-schema]
version = "1"
[types.serverType]
type="table"
[types.serverType.ip]
type="string"
pattern="^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$"
[types.serverType.role]
type="string"
[elements.title]
type="string"
[elements.owner]
type="table"
[elements.owner.name]
type="string"
[elements.owner.dob]
type="local-date"
[elements.database]
type="table"
[elements.database.enabled]
type = "boolean"
[elements.database.ports]
type = "array"
arraytype = "integer"
[elements.database.data]
type = "array"
arraytype = "array"
[elements.database.temp_targets]
type = "table"
[elements.servers]
type="collection"
typeof = "types.serverType"
minlength = 1
A TOML Schema file has the following structure:
# Metadata
[toml-schema]
# Types
[types]
# Elements
[elements]
[toml-schema]
: table with information and metadata of the schema.
[types]
: table with definition of types to be reused in elements`.
[elements]
: table with the overall structure of the TOML document, its tables, properties, and conditions.
IMPORTANT: No other top-level table or key-value pair may appear on a TOML Schema document.
[toml-schema]
This table is reserved for metadata regarding the TOML Schema itself.
[toml-schema]
version = "1.0"
# custom = "value" # *NOT allowed
[toml-schema.meta]
<any> = <value> # allowed
...
[toml-schema.meta.subtable] # allowed
# [toml-schema.custom] # *NOT allowed
...
version
: the version of this schema file. Type: string.
toml-schema.meta
: table reserved for any custom user-provided metadata.
No custom property or table may be appended under toml-schema
, only inside toml-schema.meta
table.
[elements]
The elements
table defines the overall structure and properties of the TOML document. Elements follow the same structure and rules of Types, specified below, except that elements cannot reference other elements. To reuse conditions and structures, [types]
must be defined and referenced back from the [elements]
table.
[types]
The [types]
table is for use when there is a need for custom, reusable types of structure or properties. A type
is referenced in an element
by the property typeof
.
[types]
[types.<typename>]
type = "<simple-type> | array | table | collection"
typeof = "<full-name-of-a-defined-type>"
arraytype = "<simple-type>"
allowedvalues = [ <array-with-enumeration-of-allowed-values> ]
pattern = "<string-regex-for-string-validation>"
optional = true|false
min = <any>
max = <any>
minlength = <integer>
maxlength = <integer>
<simple-type>
List of considered simple types:
any
string
integer
float
boolean
offset-date-time
local-date-time
local-date
local-time
allowedvalues
allowedvalues
provides a mechanism to set an enumeration of allowed values to be used in any given simple type.
Example:
[types.colorType]
type="string"
allowedvalues=[ "red", "black", "blue" ]
min
and max
This property may only be used when defining a value range for the following types:
array
float
integer
date
and/or time
typesminlength
and maxlength
This property may only be used when defining the allowed length of a string
, an array
, or a collection
.
any
No min/max condition may be applied to type any
. The parser must show an error if this happens.
array
table
(*)collection
(*)(*) The schema also explicitly defines two types:
table
for specifying child elements associated to the parent.collection
.For simplicity, there is no definition of inline table
since these are just tables that can be expressed inlined in a TOML document.
A table
may have a set of properties, or none at all. If a table has a definition of properties, then the parser must validate the input and the input must match exactly the rules of the table and its children.
If a property of type table
has no defined property and/or structure, the parser must not validate its input. This is useful for representing custom JSON data payloads.
Arrays can be defined by mixing the following properties:
arraytype
: the type of the value in the array (e.g. string).minlength
: the minimum length of the array (e.g. no less than 2 elements).maxlength
: the maximum length of the array (e.g. no more than 2 elements).minvalue
: the minimum value of the array (e.g. 80).maxvalue
: the maximum value of the array (e.g. 8080).allowedvalues
: enumeration of possible values.Example for schema definition:
[elements.colors]
type="array"
arraytype="string"
Example of TOML file:
colors=[ "red", "yellow", "green" ]
The minvalue
and maxvalue
conditions are used to set a valid range of values, and it may be applied only to properties where arraytype
is one of the following: integer
, float
, and the four available date
and/or time
types. Both properties are inclusive.
Dates and Times are naturally sorted by past, present, future, meaning that the first element is in the past, and the furthest element is in the future.
allowedvalues
does not have to be naturally sorted, but the lowest value must match minvalue
if it is available. The highest/furthest value must match maxvalue
if it is available.
If allowedvalues
does not match the conditions of minlength
, maxlength
, minvalue
and maxvalue
, the parser must throw an error indicating that the TOML Schema is malformed.
If arraytype
is not defined, then the type of array elements is any
, and any data type can be used and mixed together.
If type
is array
and arraytype
is of type array
, then automatically any data type can be used and mixed together.
One can set an element of type collection
for when there is a need to have multiple children with dymamic, user-provided keys or table headers.
A collection
is also a table
and, therefore, it may have nested, schema-restricted key-value pairs of simple types.
A collection
requires a type definition of the child elements. Each child must be given a unique key in the TOML document.
The types allowed in a collection may be defined with only one of the following attributes:
typeof
: a single type. Parser must validate against this type.oneof
: one type of a provided array of types. Only one type must return true
in the validation. Parser must throw an error if more than one type is valid for the input.anyof
: any type of a provided array of types. Parser stops validating at the first return of a true
validation. Parser should throw an error if input is not valid for any type.Example:
The below example shows a table servers
that is a collection
.
Each server must be given a key, and follow the defined structure of types.serverType
.
A server may also have a DNS table with user-provided key names.
TOML:
[servers]
group = "group1"
[servers.alpha]
name = "Alpha DC0"
address = "dc0.alpha"
[servers.alpha.dnstable]
cloudflare = "1.1.1.1"
google1 = "4.4.4.4"
google2 = "8.8.8.8"
internal = "mydns.intranet"
[servers.beta]
name = "Beta DC0"
address = "dc0.beta"
TOML Schema:
[types]
[types.dnsType]
type = "string"
pattern = "<ip-regex-pattern>"
[types.hostnameType]
type = "string"
pattern = "<valid-hostname-regex-pattern>"
[types.serverType]
type = "table"
[types.serverType.name]
type = "string"
[types.serverType.address]
type = "string"
[types.serverType.dnstable]
type = "collection"
anyof = [ "types.dnsType", "types.hostnameType" ]
[elements]
[elements.servers]
type = "collection"
typeof = "types.serverType"
[elements.servers.group]
type = "string"
A collection
may be represented as subtables of a common table in a TOML document.
A type may be referenced to inherit the defined rules existent in given type. Both type
and element
may reference a type
.
[types]
[types.nameType]
type="string"
pattern="[a-zA-Z]"
[types.serverType.name]
typeof = "types.nameType"
[elements]
[elements.datacenter]
type="table"
[elements.datacenter.name]
typeof="types.nameType"
[elements.datacenter.servers]
type = "collection"
typeof = "types.serverType"
optional
Properties may be defined as optional in the schema. By default, optional equals false, and the structure is required.
Parsers must only skip a structure validation if the structure is optinal in the TOML Schema and does not exist in the TOML document. For any other condition, the parser must validate the input against the schema.
pattern
This property is only used for validating string
input. Parsers must validate the input with the provided regular expression.
Parsers must support Perl/PCRE syntax. Parsers may support more extensions and other syntaxes.
It is NOT the goal of a TOML Schema to ever modify the data output of a TOML object during parsing.
A parser that validates a TOML document against a TOML Schema must produce the exact same TOML data object as a parser that does not validate.
TOML Schema files should use the extension .tosd
.
When transferring TOML Schema files over the internet, the appropriate MIME types are:
A TOML file must have this indication at the top, to reference which schema file to use for validation:
[toml-schema]
version = "1"
location = "<uri>"
Where <uri>
can be a remote URL (e.g. https) or a local file.
Only simple built-in types are allowed.
If you want to share your thoughts on this proposal, please go to the General Discussion.
There is an ongoing effort to bring Schema support for TOML under the PR 116. I found that proposal to be extensively detailed and well constructed, but I believe this simpler proposal to be more realistic.
Thanks to my friends!