Reified.Schema.Contracts.Build 0.3.0

dotnet add package Reified.Schema.Contracts.Build --version 0.3.0
                    
NuGet\Install-Package Reified.Schema.Contracts.Build -Version 0.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Reified.Schema.Contracts.Build" Version="0.3.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Reified.Schema.Contracts.Build" Version="0.3.0" />
                    
Directory.Packages.props
<PackageReference Include="Reified.Schema.Contracts.Build">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Reified.Schema.Contracts.Build --version 0.3.0
                    
#r "nuget: Reified.Schema.Contracts.Build, 0.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Reified.Schema.Contracts.Build@0.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Reified.Schema.Contracts.Build&version=0.3.0
                    
Install as a Cake Addin
#tool nuget:?package=Reified.Schema.Contracts.Build&version=0.3.0
                    
Install as a Cake Tool

<p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="docs/content/img/reified-logo-dark.svg"> <img src="docs/content/img/reified-logo-light.svg" alt="Reified" width="420"> </picture> </p>

Declare value and model invariants once. Derive validation, parsing, diagnostics, codecs, contracts, and test data from the same declarations.

ci release NuGet License

How the packages fit

<pre> Constraint ─┐ Parse ──────┤ Data ───────┼──> Schema ───> Schema.Json Refinements ┘ └──> contract tooling </pre>

Install Schema when structured input must become a model. Constraint, Parse, Data, and Refinements can each be used alone without Schema, but they are designed to work together consistently.

Why Reified

Reified means “made concrete”: the library turns a model's rules into data that validation, codecs, contracts, and tests can share.

Most boundary code repeats the same facts in validators, decoders, error handling, API contracts, and tests. Reified keeps those facts in one typed declaration and lets each job read from it.

  • Type-safe data refinement and narrowing functions — once a value has passed its rules, represent that fact in its type instead of checking it again throughout the application.
  • Hierarchical error accumulation — get a structured, keyed diagnostic tree that keeps property names and collection indexes intact, so an API or UI can put each message in the right place.
  • One definition of the model — parsing, validation, JSON codecs, JSON Schema, contracts, and generated test data share field names, shapes, and rules.
  • Compatible discriminated unions — use a tooling-friendly default for new JSON, or describe the established representation when integrating with an existing serializer.
  • Schema derivation for boundary records — generate the declaration at build time when a record already contains the necessary wire-format rules.
  • First-class AOT compilation and Fable support through explicit schemas — avoid runtime reflection, run the same model on .NET, and compile it to JavaScript.

Declare the rule once

Most validation stacks keep the rule and its message in separate places. Reified makes a constraint inspectable data, so checking, diagnostics, export, and generation read the same declaration.

open Reified

let retryCount : Constraint<int> =
    Constraint.between 0 10

3 |> Constraint.check retryCount
// Ok ()

42
|> Constraint.check retryCount
|> Result.mapError Violation.render
// Error "expected a value between 0 and 10, but was 42"

Nobody wrote the failure sentence separately. Change the bounds and every interpreter observes the new rule.

Declare a whole model

A schema describes how structured input becomes a model. It returns the typed value only after every field and constructor invariant succeeds.

open Reified
open Reified.ConstraintDSL
open Reified.SchemaDSL

type Signup =
    { Email: string
      Age: int }

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

match Schema.parse signupSchema input with
| Ok signup -> register signup
| Error errors -> display errors

The same signupSchema can drive a compiled JSON codec, JSON Schema, form metadata, versioned migrations, and matching test data.

Read and write JSON from that same declaration

You do not write a second description of the wire shape. Json.compile turns the schema you already have into a codec that both encodes and decodes.

open Reified.Schema.Json

let codec = Json.compile signupSchema   // compile once, typically at startup

Json.serialize codec { Email = "ada@example.com"; Age = 36 }
// {"email":"ada@example.com","age":36}

Json.deserialize codec """{"email":"ada@example.com","age":36}"""
// { Email = "ada@example.com"; Age = 36 }

match Json.tryDeserialize codec """{"email":"ada@example.com","age":"thirty"}""" with
| Ok signup -> Some signup
| Error message -> None   // JSON decode failed at $.age: expected digit

The codec is compiled from the schema's typed field plan, so there is no runtime reflection and it stays AOT-, trimming-, and Fable-safe. It is the trusted-path counterpart to Schema.parse: it enforces the wire shape but skips constraint checking, because payloads from producers you trust already passed those checks. Untrusted input still goes through Schema.parse, which accumulates every violation with its path.

Or derive the schema from the record itself

For wire records — DTOs whose whole job is to cross a boundary — declaring the schema by hand is duplication. Mark the record instead:

open Reified.DerivedSchema

[<DeriveSchema>]
type Signup =
    { [<Present; Email>]
      Email: string
      [<AtLeast 13>]
      Age: int }

Signup.schema     // Schema<Signup>
Signup.parse      // Data -> Result<Signup, SchemaErrors>
Signup.validate   // Signup -> Result<Signup, SchemaErrors>

This is the same schema as the handwritten one above — not an equivalent one. Reified.Schema.Contracts.Build reads the attributes from F# source at build time and generates ordinary constructor-last Schema DSL, which then compiles normally. The attributes are inert metadata; nothing is reflected over at runtime, and everything downstream — parsing, JSON codecs, JSON Schema, test data — works exactly as it does for a schema you wrote by hand.

Derivation is the preferred approach for DTOs. Keep it to public, permissive boundary records, and map the parsed result through a domain constructor so real invariants live in refined values and domain types rather than on the wire record.

Packages

Install Reified to get the complete runtime set. For the integrated boundary model, start with Reified.Schema and add its interpreters as needed:

  • Reified — umbrella package that references all runtime packages
  • Reified.Schema — structured model admission, diagnostics, inspection, and JSON Schema
  • Reified.Schema.Json — compiled JSON codecs
  • Reified.Schema.Contracts.Build — MSBuild integration for derived record and wire contracts

Schema builds on focused packages that remain useful by themselves:

  • Reified.Constraint — reusable, inspectable value rules and structured violations
  • Reified.Refinements — types that carry an invariant after construction
  • Reified.Parse — serialized primitive decoding
  • Reified.Data — portable structured input and test data

Reified.Result is independent composition over the standard F# Result type. It works with Reified APIs but is not part of Schema's dependency chain.

The contract compiler and schema-derived testing adapter are repository tooling, not runtime packages.

Reified.Schema.Contracts.Build is not in the umbrella. MSBuild targets do not travel through a transitive package reference, so a project that derives schemas at build time references it directly.

Documentation

Axial integration

Axial describes asynchronous workflows with explicit failures and dependencies. Reified began as a library inside Axial and was forked out to stand alone; neither core depends on the other.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.3.0 0 8/26/2026
0.2.0 34 8/25/2026
0.1.0 64 8/17/2026