Repository F# setup
open Reified
open Reified.Refinements
open Reified.Result

Using Data with the rest of Reified

Every schema parse takes a Data value, so any source that can become Data can feed a schema.

Feeding a schema

Verified
open Reified
open Reified.DataDSL
open Reified.SchemaDSL
open Reified.ConstraintDSL

type Signup = { Email: string; Age: int }

let signupSchema =
    schema<Signup> {
        field _.Email { constraints [ email ] }
        field _.Age
        construct (fun email age -> { Email = email; Age = age })
    }

let input =
    data [
        "email" => "ada@example.com"
        "age" => 42
    ]

let parsed = Schema.parse signupSchema input
Requires & types
Requires: open Reified; open Reified.ConstraintDSL; open Reified.DataDSL; open Reified.SchemaDSL (packages: Reified.Constraint, Reified.Data, Reified.Schema)
val signupSchema: Schema<Signup>
val input: Data
val parsed: Result<Signup,SchemaErrors>

The same schema accepts input from Data.ofJsonDocument for a request body, Data.ofNameValues for a form post, Data.ofCliArgs for a command line, Data.ofConfiguration or Data.ofEnvironment for settings, and Data.mergeAll for several of those layered together. The schema does not depend on the source.

Adapters produce different trees. JSON carries typed Booleans and numbers, while form, CLI, and configuration adapters leave supplied non-null strings as text for the schema to parse. Accepted null strings and sparse gaps remain Data.Null. Repeated names build a list in ofNameValues but overwrite in ofConfiguration, where lists come from canonical ASCII decimal key segments instead (0 or [1-9][0-9]*). Environment/configuration adapters share bounded list length, output-node count and path depth; configure positive overrides for larger trusted inputs with Data.ofConfigurationWith or the environment options' Limits record. CLI flags arrive as the text "true" or "false". The same schema accepts input from any of them, but sources must agree on the resulting tree, not just the logical content. See the adapter rules for what each one produces.

A fixture written with data [ ... ] exercises the same parse path as production JSON without a serializer.

Redisplay and error reporting

Schema.parseRetainingInput keeps the original Data alongside the parse result, so a failed form round-trip can re-show exactly what the user typed next to each field error. The paths in schema diagnostics (address.city, lines[2].quantity) address the input tree. Data.redisplayPath (string form) or Data.redisplayAt (DataPath form) recovers the raw fragment at any of them.

See redisplay and field errors for the full pattern.

Boundary adapters

An adapter builds Data from a source such as route values, query strings, headers, or a JSON body before any schema is involved. Supporting another source means producing Data; every schema and interpreter downstream stays unchanged.