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

Schema Integration

Schema describes structured input: fields, wire representations, path-aware failures, accumulation, and reconstruction. A refinement supplies the value-level step that turns an already-decoded underlying value into an invariant-carrying domain value. Schema can apply that refinement at a field boundary and report its failures at the field's path.

Reified.Refinements has no Schema dependency. Domain types can define refinements without choosing a wire format; an application that uses Reified.Schema decides where those refinements participate in structured decoding and encoding.

The Schema quickstart introduces fields, record construction, and path-aware diagnostics. Then read Refined Values in Schema for canonical field schemas, raw-value constraints, explicit refinement, and schema-local restrictions. This page is the shorter API-oriented view of that integration.

Refine a primitive schema

open Reified.Refinements
open Reified

let nameSchema : Schema<NonBlankString> =
    Schema.text
    |> Schema.refine NonBlankString.refinement

Parsing checks the underlying string, constructs NonBlankString, and reports failures at the schema path. Encoding and checking project through NonBlankString.Value.

A numeric range is a constraint rather than a refined type, so it goes on the primitive:

field _.Quantity { constrain (Constraint.greaterThan 0) }

Schema.constrain is available for a standalone value schema too, but inside a field block the schema is inferred from the field's type and each constraint sits on its own line.

For an application type:

let emailSchema : Schema<ContactEmail> =
    Schema.text
    |> Schema.refine ContactEmail.refinement

A field block receives the refinement explicitly:

let signupSchema =
    schema<Signup> {
        field _.Email {
            withSchema Schema.text
            refine ContactEmail.refinement
        }

        field _.Age
        construct Signup.create
    }

Choose the operation by meaning

  • Schema.refine refinement schema constructs an invariant-carrying destination and retains refinement metadata.
  • Schema.convert forward backward schema performs a total projected mapping.
  • Schema.tryConvert forward backward schema performs a fallible projected mapping returning SchemaError list.
  • Schema.admit create project draftSchema constructs a domain model from a structured draft while preserving fields.
let centsSchema : Schema<decimal> =
    Schema.int
    |> Schema.convert decimal int
let bookingSchema : Schema<Booking> =
    bookingDraftSchema
    |> Schema.admit Booking.create Booking.toDraft

For the complete progression from a raw field schema to a canonical refined field, continue to Refined Values in Schema.