Axial is a set of F# libraries with three entry points:
- Error Handling — four focused packages:
Axial.Result(Result composition andresult { }),Axial.Check(reusable value checks),Axial.Parse(serialized primitive decoding), andAxial.Refined(invariant-carrying domain values); - Schema for turning structured input into domain values, with path-aware accumulated diagnostics;
- Flow for async work with explicit dependencies and expected failures.
Install each focused package on its own, install Axial.ErrorHandling for Result, Check, Parse, and Refined together, or
install Axial for Error Handling and Schema together.
Warning
Axial 0.7.0 is the first planned release under the Axial name. It replaces the former monolithic FsFlow package with smaller packages. The public surface is still pre-1.0 and may change.
Error Handling is four focused packages that keep ordinary Result<'value, 'error> in your interfaces: Axial.Result
for Result composition, Axial.Check for reusable value checks, Axial.Parse for serialized primitive decoding, and
Axial.Refined for invariant-carrying domain values. Install any focused package independently; none requires
Axial.Result.
open Axial.Check
open Axial.Check.CheckDSL
let requireName value =
value
|> Result.guard present
|> Result.mapError (fun _ -> NameMissing)dotnet add package Axial.Result # Result composition and result { }
dotnet add package Axial.Check # reusable checks and portable constraints
dotnet add package Axial.Parse # serialized primitive parsing
dotnet add package Axial.Refined # invariant-carrying domain values
dotnet add package Axial.ErrorHandling # installs all fourA schema describes fields, parsing, constraints, and construction in one value:
open Axial.Schema
open Axial.Schema.Syntax
type Signup =
{ Email: string
Age: int }
let signupSchema =
Schema.define<Signup>
|> field "email" _.Email
|> constrain emailFormat
|> field "age" _.Age
|> constrain (atLeast 13)
|> construct (fun email age -> { Email = email; Age = age })
match (Schema.parse signupSchema dataInput) with
| Ok signup -> register signup
| Error diagnostics -> display diagnosticsSchema.parse either returns the model or path-aware diagnostics. The same declaration can drive checking, JSON
Schema, compiled codecs, form redisplay, test-data generation, and versioned wire contracts.
A schema only controls values produced through the schema. When every value of a type must satisfy an invariant, use a private representation and expose a fallible constructor or named domain operations.
Start here:
- Schema overview
- Getting started with Schema
- Construction guarantees
- Recommended Schema patterns
- Versioned wire contracts
Install the core package:
dotnet add package Axial.SchemaFlow<'env, 'error, 'value> describes async work, its dependencies, and its expected failure type:
open Axial.Flow
type RegistrationError =
| UserNotFound
| SaveFailed of string
type RegistrationEnv =
{ LoadUser: int -> Task<Result<User, RegistrationError>>
SaveUser: User -> Task<Result<unit, RegistrationError>> }
let register userId : Flow<RegistrationEnv, RegistrationError, unit> =
flow {
let! loadUser = Flow.read _.LoadUser
let! saveUser = Flow.read _.SaveUser
let! user = loadUser userId
return! saveUser user
}Tests supply a small record of fakes. The application host supplies live implementations. Cancellation, resource scopes, retries, and child fibers stay within the workflow runtime.
Start here:
Install Flow:
dotnet add package Axial.FlowThe authored schema and workflow paths avoid runtime reflection. The core packages support NativeAOT, trimming, and Fable; individual host and service packages document their supported targets.