Repository F# setup
open Reified
open Reified.Refinements
open Reified.ResultConstraints and localization in schemas
Install Reified.Schema (dotnet add package Reified.Schema); it depends on Reified.Constraint.
Open Reified for Schema, Constraint, Data, Renderer, and the error types; open Reified.SchemaDSL for record fields and Reified.ConstraintDSL for unqualified rule names.
A field block's constrain and constraints operations attach the same Constraint<'value> you can use with Constraint.check. Schema.constrain attaches one to a standalone value schema. Refined fields can use a refinement's constraint and add boundary-specific rules. A successfully parsed value passes those rules; a failed rule produces a Violation, not a parse error. Schema.parse returns SchemaErrors: each SchemaIssue pairs a SchemaPath with a SchemaError, including SchemaError.Violation for failed constraints. Parse, missing-field, and structural errors remain distinct cases.
open Reified
open Reified.SchemaDSL
open Reified.ConstraintDSL
type Signup = { Name: string }
let signup =
schema<Signup> {
field _.Name {
constrain present
}
construct (fun name -> { Name = name })
}
let french =
Map.ofList
[ "constraint.presence.present", "doit être renseigné"
"attribute.name", "Nom" ]
let renderer = Renderer.ofLookup french.TryFind |> Renderer.context "signup"
match Schema.parse signup (Data.ofNameValues [ "name", "" ]) with
| Error errors ->
let messages = errors |> SchemaErrors.fullMessages renderer
let path, message = List.head messages
assert (SchemaPath.format path = "name")
assert (message = "Nom doit être renseigné")
| Ok _ -> failwith "Expected a missing name"
ReifiedReified.SchemaDSLThe concise schema-definition vocabulary: the record computation expression, its field and constructor forms, and the collection-schema operations. Optional and opt-in, in the same shape as Reified.DataDSL and Reified.ConstraintDSL: open Reified.Schema for Schema, then open Reified.SchemaDSL for this vocabulary. There is no constraint catalogue here. One Constraint vocabulary serves direct checking, refinement, and Schema, so a field block reaches for Constraint.email or an opened Reified.ConstraintDSL exactly as standalone code does. Boundary supply is Schema-owned and stays here as mustSupply and mayOmit.
Reified.ConstraintDSLConstraint constructors usable without the Constraint. prefix inside a module that declares value rules. Optional vocabulary, not another abstraction. Opening it makes a declaration read minLength 3 instead of Constraint.minLength 3; everything here is the same value the qualified name returns. Some constructors are deliberately left out because they shadow names the same validation code is likely to need in scope: contains, distinct, all, any, length, and between shadow core F# operations. Reach for those as Constraint.contains, Constraint.all, and so on, even inside a module that has opened this DSL. Constraint execution (Constraint.satisfies, Constraint.check, Constraint.guard) is likewise always qualified: ConstraintDSL declares constraints, Constraint.* executes and inspects them. orError and mapError are structural adapters matching the corresponding Result operations. They let a constraint pipeline retain its input and finish with the application's error type without adding an Reified.Result dependency. module SignupRules = open Reified.ConstraintDSL let age : Constraint<int> = atLeast 13 let contact : Constraint<string> = Constraint.all [ present; email ] let requireContact value = value |> Constraint.guard contact |> orError EmailRequired
FsLiveDocsGeneratedPage7_10EA2B4D0E31.SignupName: stringstringAn abbreviation for the CLI type . Basic Types
signup: Schema<Signup>schema: SchemaCeBuilder.SchemaBuilder<'model>Record-schema computation expression.
``.ctor``: Quotations.Expr<(Signup -> string)> -> field<Signup,string>Declares a field, deriving its camel-cased wire name from the property getter. type Signup = { Email: string } field (fun (s: Signup) -> s.Email) // wire name "email"
``.ctor``: Quotations.Expr<('model -> 'target)> -> field<'model,'target>Declares a field, deriving its camel-cased wire name from the property getter. type Signup = { Email: string } field (fun (s: Signup) -> s.Email) // wire name "email"
_arg1: SignupConstrain: SchemaFieldSteps.FieldInitial<Signup,string> * Constraint<string> -> SchemaFieldSteps.FieldConfigured<Signup,string>Adds a portable constraint to the field's current schema value.
present: Constraint<^value>Alias for .
construct: 'constructor -> SchemaCeBuilder.ConstructorStep<'model,'constructor>Closes a record schema with a total constructor.
name: stringfrench: Map<string,string>Microsoft.FSharp.Collections.MapModuleContains operations for working with values of type .
ofList: ('Key * 'T) list -> Map<'Key,'T>Returns a new map made from the given bindings. The input list of key/value pairs. The resulting map. let input = [ (1, "a"); (2, "b") ] input |> Map.ofList // evaluates to map [(1, "a"); (2, "b")]
renderer: RendererReified.RendererModuleBuilds renderers and renders messages through them.
ofLookup: MessageLookup -> RendererA renderer backed by any key-to-template lookup. The portable constructor, and the one Fable applications use. let translations : Map<string, string> = Map.empty let renderer = Renderer.ofLookup translations.TryFind
TryFind: string -> string optionLookup an element in the map, returning a Some value if the element is in the domain of the map and None if not. The input key. The mapped value, or None if the key is not in the map. let sample = Map [ (1, "a"); (2, "b") ] sample.TryFind 1 // evaluates to Some "a" sample.TryFind 3 // evaluates to None
(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
context: string -> Renderer -> RendererAppends a document, model, form, or component segment. let signup = renderer |> Renderer.context "signup"
Reified.SchemaConstruction, composition, parsing, and checking for universal schemas.
parse: Schema<'a> -> Data -> Result<'a,SchemaErrors>Parses source-neutral structured data, runs constraints and refinements, and invokes record constructors.
Reified.DataModuleofNameValues: (string * string) seq -> DataBuilds object-shaped data from name and value pairs.
ErrorRepresents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
errors: SchemaErrorsmessages: (SchemaPath * string) listReified.SchemaErrorsModuleFunctions for inspecting and rendering accumulated schema failures.
fullMessages: Renderer -> SchemaErrors -> (SchemaPath * string) listRenders each failure as a complete fragment with its attribute noun, paired with its path. For API payloads and anywhere else without an adjacent label. At SchemaPath.root the noun comes from constraint.attribute.default; the document context is never used as a noun. errors |> SchemaErrors.fullMessages (renderer |> Renderer.context "signup") // [ SchemaPath "name", "Name must be present" ]
path: SchemaPathmessage: stringMicrosoft.FSharp.Collections.ListModuleContains operations for working with values of type . Operations for collections such as lists, arrays, sets, maps and sequences. See also F# Collection Types in the F# Language Guide.
head: 'T list -> 'TReturns the first element of the list. The input list. Thrown when the list is empty. The first element of the list. let inputs = ["banana"; "pear"] inputs |> List.head Evaluates to banana [] |> List.head Throws ArgumentException
Reified.SchemaPathModuleFunctions for building and formatting schema error paths.
format: SchemaPath -> stringFormats a path with dot-separated keys and bracketed indexes.
(=): 'T -> 'T -> boolStructural equality The first parameter. The second parameter. The result of the comparison. 5 = 5 // Evaluates to true 5 = 6 // Evaluates to false [1; 2] = [1; 2] // Evaluates to true (1, 5) = (1, 6) // Evaluates to false
OkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
failwith: string -> 'TThrow a exception. The exception message. Never returns. let failingFunction() = failwith "Oh no" // Throws an exception true // Never reaches this failingFunction() // Throws a System.Exception
Requires & types
Requires: open Reified; open Reified.ConstraintDSL; open Reified.SchemaDSL (packages: Reified.Constraint, Reified.Data, Reified.Schema)val signup: Schema<Signup>val french: Map<string,string>val renderer: RendererSchemaErrors.messages returns bare predicates alongside paths for forms with their own labels; fullMessages includes the localized attribute noun. Schema supplies the field path as the renderer attribute, so provide the document context, not Renderer.attribute for each issue. Untranslated keys fall back to neutral English. Choose Renderer.english for English without resources, Renderer.ofLookup for portable translations, or a resource-manager constructor on .NET with an explicit culture. Custom rules need Constraint.customLocalized and their own catalogue entry to translate; authored prose stays as written. To add a language, generate and fill catalogue entries for both Catalogue (constraints) and SchemaMessages (schema failures).
Read Constraints for the value-rule vocabulary and Localization for renderer setup, context/fallback, custom rules, and the language workflow. Redisplay and field errors covers presenting the paths in a form.