On this page:
2.1 Basic TOML DSL
toml
toml-ref
2.2 Custom TOML DSLs
2.2.1 Basic usage (no validation)
2.2.2 With a schema
2.2.3 Using additional bindings in the schema
2.3 Low-level APIs
2.3.1 Validation
define-toml-schema
exn:  fail:  toml:  validation
2.3.2 Syntax reader
make-toml-syntax-reader
get-info
9.0.0.6

2 Module Reference🔗ℹ

2.1 Basic TOML DSL🔗ℹ

 #lang toml/config package: toml-config-lib

A #lang for parsing TOML files into Racket modules. Files using #lang toml/config are parsed as TOML and provide the result as a hash table.

value

toml : hash?

The parsed TOML data, represented as an immutable hash table with symbol keys. Tables become nested hash tables, and all TOML data types are converted to their Racket equivalents.

procedure

(toml-ref data    
  path-component ...    
  [#:default default])  any/c
  data : hash?
  path-component : (or/c symbol? exact-nonnegative-integer?)
  default : any/c = (λ () (error ...))
Variadic convenience function for accessing nested TOML values using a path of keys and array indices.

Path components can be:
  • Symbols (possibly dotted): traverse into hash tables

  • Exact non-negative integers: index into lists

If any key in the path is missing or an array index is out of bounds, default is returned (or called if it’s a procedure).

; Dotted key notation
(toml-ref data 'database.host)
; equivalent to:
(hash-ref (hash-ref data 'database) 'host)
 
; Array indexing
(toml-ref data 'database.replicas 0 'host)
; equivalent to:
(hash-ref (first (hash-ref (hash-ref data 'database) 'replicas)) 'host)
 
; With defaults
(toml-ref data 'missing.key #:default "fallback")
; => "fallback"
(toml-ref data 'replicas 99 'host #:default "n/a")
; => "n/a"

2.2 Custom TOML DSLs🔗ℹ

 (require toml/config/custom) package: toml-config-lib

A module language for quickly creating custom TOML-based #langs with validation.

When you use #lang toml/config/custom as a module language (in a reader submodule), it provides a #%module-begin that handles all the reader plumbing for you. You just specify an optional schema, and it generates a read-syntax macro and provides the get-info function automatically.

The module language also provides common predicates and contracts that are useful in schemas: everything from racket/base, racket/contract/base, and non-empty-string?.

2.2.1 Basic usage (no validation)🔗ℹ

The simplest custom reader just parses TOML without any validation:

"myapp/config.rkt"

#lang racket/base
 
(module reader toml/config/custom)

Now TOML files can use #lang myapp/config (assuming this module is present in a package that uses the myapp collection) and they’ll get the same behavior as #lang toml/config.

2.2.2 With a schema🔗ℹ

To add validation that takes place at compile time, use the #:schema keyword inside the reader submodule, followed by field specifications:

"myapp/config.rkt"

#lang racket/base
 
(module reader toml/config/custom
 #:schema ([title string? required]
           [port (integer-in 1 65535) (optional 8080)]
           [database (table
                       [host string? required]
                       [port integer? required])]))

See define-toml-schema for info on the field-spec syntax.

By default, the schema expression inside a #lang toml/config/custom module has access to bindings from racket/base, racket/contract/base and to non-empty-string? from racket/string.

2.2.3 Using additional bindings in the schema🔗ℹ

You can add require and/or define statements in front of the #:schema keyword. This allows you to use custom predicates/contracts in your schema expression.

For example:

"myapp/example.rkt"

#lang racket/base
 
(module reader toml/config/custom
  (require gregor)
  (define (even-day? v) (and (date-provider? v) (even? (->day v))))
  #:schema [(birthdate even-day? required)])

You can also use module* with (require (submod "..")) to bring parent bindings into scope:

"myapp/example.rkt"

#lang racket/base
 
(define (valid-port? n)
 (and (integer? n) (>= n 1024) (<= n 65535)))
 
(provide valid-port?)
 
(module* reader toml/config/custom
 (require (submod ".."))
 #:schema ([title string? required]
           [port integer? valid-port? (optional 8080)]))

2.3 Low-level APIs🔗ℹ

Most people won’t need more than toml/config/custom to implement their own TOML DSLs. But if you want more control over the reader implementation, or if you’re not using toml/config/custom as a module language, you can use these lower-level functions directly.

Here’s an example using module+ to create a reader submodule that accesses custom predicates from the parent module:

"myapp/config.rkt"

#lang racket/base
 
(define (valid-title? s)
 (and (string? s)
      (> (string-length s) 0)
      (<= (string-length s) 50)))
 
(define (valid-port? n)
 (and (integer? n)
      (>= n 1024)
      (<= n 65535)))
 
(module+ reader
 (require toml/config/schema
          toml/config/reader)
 (provide read-syntax get-info)
 
 (define-toml-schema compiled-schema
   [title string? valid-title? required]
   [port integer? valid-port? (optional 8080)])
 
 (define read-syntax
   (make-toml-syntax-reader compiled-schema)))

Note that when using the low-level APIs, you need to provide both read-syntax and get-info yourself (whereas toml/config/custom does this automatically).

2.3.1 Validation🔗ℹ

 (require toml/config/schema) package: toml-config-lib

This module provides the framework for validating hash tables against a schema, with friendly error messages. A schema can make use of simple predicates or flat contracts, but no contracts are actually installed.

A validator is a function that takes a hash table (such as parsed TOML data) and either returns a value (typically a hash table, but not required) or raises an exception if validation fails. Validators created with define-toml-schema also apply default values to the data before returning it.

syntax

(define-toml-schema id field-spec ...)

 
field-spec = [key type-check ... req-or-opt]
  | [key (table field-spec ...) maybe-req-or-opt]
  | [key (array-of table field-spec ...) req-or-opt]
     
req-or-opt = required
  | optional
  | (optional default-expr)
     
maybe-req-or-opt = 
  | required
  | optional
Creates a validator function bound to id.

Each named key is followed by one or more type-check predicates (or flat contracts) that are applied to the value supplied for the key.

Ending a field-spec with required causes an exception to be thrown if the key is not present. Ending with optional allows the key to be absent; use (optional default-expr) to give the key a default value when not supplied. Note that the default value is not checked against the type-check expressions.

A table field-spec validates a nested table with its own field specs. It can be followed by required or optional; if neither is specified, required is assumed. When a table is optional and missing, its field validations are skipped.

An array-of table field-spec validates an array of tables (TOML’s [[name]] syntax). Each element in the array is validated against the nested field specs. Defaults are applied to each array element individually.

Type checks can be any predicate (e.g. string?, integer?) or flat contract (e.g. (integer-in 1 100), (listof string?), (or/c "ascending" "descending")).

The resulting validator checks that all required keys are present, validates types for all present keys, applies default values for missing optional keys and returns the (possibly modified) hash table.

Examples:
> (define-toml-schema my-schema
    [name string? required]
    [age (integer-in 0 150) required]
    [email string? optional]
    [admin boolean? (optional #f)]
    [settings (table
                [theme string? required]
                [notifications boolean? (optional #t)])])
> (define toml-1
    (string-append*
      (add-between
       '("name = \"Alice\""
         "age = 30"
         "[settings]")
        "\n")))
> (my-schema (parse-toml toml-1))

settings.theme: required key is missing

  → Add 'theme = <value>' to the configuration

> (define toml-2
    (string-append*
      (add-between
       '("name = \"Alice\""
         "age = 30"
         "[settings]"
         "theme = \"red\"")
        "\n")))
> (my-schema (parse-toml toml-2))

'#hasheq((admin . #f)

         (age . 30)

         (name . "Alice")

         (settings . #hasheq((notifications . #t) (theme . "red"))))

Arrays of tables are validated with array-of:

Examples:
> (define-toml-schema products-schema
    [products (array-of table
                [name string? required]
                [sku integer? required]
                [color string? (optional "black")])
              required])
> (define products-toml
    (string-append*
     (add-between
      '("[[products]]"
        "name = \"Hammer\""
        "sku = 738594937"
        "color = \"red\""
        ""
        "[[products]]"
        "name = \"Nail\""
        "sku = 284758393")
       "\n")))
> (products-schema (parse-toml products-toml))

'#hasheq((products

          .

          (#hasheq((color . "red") (name . "Hammer") (sku . 738594937))

           #hasheq((color . "black") (name . "Nail") (sku . 284758393)))))

Arrays of tables can be nested:

Examples:
> (define-toml-schema fruits-schema
    [fruits (array-of table
              [name string? required]
              [varieties (array-of table
                           [name string? required])
                         optional])
            required])
> (define fruits-toml
    (string-append*
     (add-between
      '("[[fruits]]"
        "name = \"apple\""
        ""
        "[[fruits.varieties]]"
        "name = \"red delicious\""
        ""
        "[[fruits.varieties]]"
        "name = \"granny smith\""
        ""
        "[[fruits]]"
        "name = \"banana\"")
       "\n")))
> (fruits-schema (parse-toml fruits-toml))

'#hasheq((fruits

          .

          (#hasheq((name . "apple")

                   (varieties

                    .

                    (#hasheq((name . "red delicious"))

                     #hasheq((name . "granny smith")))))

           #hasheq((name . "banana")))))

struct

(struct exn:fail:toml:validation (message
    continuation-marks
    key-path
    expected
    actual)
    #:extra-constructor-name make-exn:fail:toml:validation)
  message : string?
  continuation-marks : continuation-mark-set?
  key-path : (listof symbol?)
  expected : any/c
  actual : any/c
Exception raised when TOML validation fails.

The key-path field contains the path to the problematic key as a list of symbols (e.g., '(database host) for database.host).

The expected and actual fields contain the expected type/value and the actual value that failed validation.

2.3.2 Syntax reader🔗ℹ

 (require toml/config/reader) package: toml-config-lib

procedure

(make-toml-syntax-reader validator)

  (-> any/c input-port? syntax?)
  validator : (-> hash? any/c)
Creates a read-syntax function for a TOML reader.

The validator is a validator function (typically created with define-toml-schema, but can be any function that takes a hash table). It’s called on the parsed TOML data before the module is created.

The returned function handles:
  • Reading the entire input port as a string

  • Parsing the TOML using parse-toml

  • Running the validator, converting any parse and validation errors to syntax errors

  • Generating a module that provides a toml binding

(define-toml-schema my-schema
  [title string? required])
 
(define read-syntax
  (make-toml-syntax-reader my-schema))

procedure

(get-info in mod-path line col pos)  (-> any/c any/c any/c)

  in : input-port?
  mod-path : module-path?
  line : (or/c #f exact-positive-integer?)
  col : (or/c #f exact-nonnegative-integer?)
  pos : (or/c #f exact-positive-integer?)
Returns a function that provides metadata about the TOML language to DrRacket and other tools. Currently supports 'color-lexer for TOML syntax highlighting in DrRacket.

This function is automatically provided by toml/config/custom, but if you’re implementing a reader using the low-level APIs with a manual reader submodule, you need to provide it yourself. This will ensure DrRacket applies sensible syntax coloring for your custom TOML #langs.

See Source-Handling Configuration for more information about get-info and reader extensions.