Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Layers
open Axial.Console
open Axial.FileSystem
open Axial.Hosting
open Axial.Hosting.Browser
open Axial.Hosting.Node
open Axial.HttpClient
open Axial.PlatformService
open Axial.Process
open Axial.State
open Axial.Telemetry
open Axial.Telemetry.JavaScriptPolicy and verification
Use a Policy to define a named verification rule that a workflow can apply to an input value. Run the rule inside a
workflow with Flow.verify.
A policy has this shape:
Policy<'env, 'error, 'input, 'output>'env -> 'input -> Result<'output, 'error>'envis the workflow environment that the policy can read.'erroris the expected workflow error returned when verification fails.'inputis the value to verify.'outputis the verified or transformed value returned on success.
Defining a policy does not run a Flow. A policy is a reusable function value. Flow.verify policy input creates a
Flow that supplies the current workflow environment to the policy when the Flow runs. Ok output continues the
workflow, and Error error short-circuits it through the typed error channel.
Define and run a policy
The following policy checks a limit from the workflow environment:
type AppEnv =
{ EnforceLimit: bool
Limit: int }
type OrderError = TooLarge
let withinLimit : Policy<AppEnv, OrderError, int, int> =
fun env count ->
if count <= env.Limit then Ok count
else Error TooLarge
let placeOrder count =
flow {
let! checkedCount =
count
|> Flow.verify withinLimit
return checkedCount
}
04-error-handling_02-policy.md_page.AppEnvEnforceLimit: boolboolAn abbreviation for the CLI type . Basic Types
Limit: intintAn abbreviation for the CLI type . Basic Types
04-error-handling_02-policy.md_page.OrderErrorTooLargewithinLimit: Policy<AppEnv,OrderError,int,int>PolicyRepresents an environment-aware requirement that turns an input into either an output or a workflow error. The workflow environment available to the policy. The workflow error produced by the policy. The input value checked by the policy. The output value produced by the policy.
env: AppEnvcount: int(<=): 'T -> 'T -> boolStructural less-than-or-equal comparison The first parameter. The second parameter. The result of the comparison. 5 <= 1 // Evaluates to false 5 <= 5 // Evaluates to true [1; 5] <= [1; 6] // Evaluates to true
OkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
ErrorRepresents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
placeOrder: int -> Flow<AppEnv,OrderError,int>flow: FlowBuilderThe universal flow { } computation expression.
checkedCount: int(|>): '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
Axial.Flowverify: Policy<'env,'error,'input,'output> -> 'input -> Flow<'env,'error,'output>Creates a flow that verifies an input with an environment-aware policy. When the Flow runs, verify supplies its current environment to the policy. An Ok result succeeds with the policy output. An Error result short-circuits the workflow through its typed error channel. The reusable verification rule to apply. The input value to verify. A cold flow that succeeds or fails with the policy result.
Adapt an existing function
Use a Policy constructor when you already have a function that returns Result:
| Function | Use it when |
|---|---|
Policy.lift operation mapError |
The operation does not need the environment and its error must be mapped. |
Policy.withError operation error |
The operation does not need the environment and any failure has one workflow error. |
Policy.context operation mapError |
The operation reads the environment and its error must be mapped. |
For example, Policy.withError assigns a workflow error to a validation function whose error is unit:
let requireNonBlank value =
if System.String.IsNullOrWhiteSpace value then Error ()
else Ok value
let requireName =
Policy.withError requireNonBlank NameRequired
let register name =
flow {
let! checkedName = name |> Flow.verify requireName
return checkedName
}Use Policy.compose first second to run two policies from left to right. The second policy receives the successful
output of the first. The first error stops the composition.
let normalizedName =
Policy.compose requireName normalizeNamePolicy.pass returns its input unchanged. Use it when a composition requires a policy but no verification is needed.
Enable a policy from the environment
Use Policy.optional enabled policy when the environment decides whether a policy applies:
let orderLimit =
withinLimit
|> Policy.optional _.EnforceLimit
orderLimit: Policy<AppEnv,OrderError,int,int>withinLimit: Policy<AppEnv,OrderError,int,int>(|>): '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
Axial.PolicyModuleConstructors and combinators for environment-aware workflow requirements.
optional: ('env -> bool) -> Policy<'env,'error,'input,'input> -> 'env -> 'input -> Result<'input,'error>Runs a policy only when the environment predicate is true; otherwise returns the input unchanged.
_arg1: AppEnvEnforceLimit: boolChoose between Policy and Bind
Use Policy when a verification rule has a domain name, appears in multiple workflows, reads the environment,
composes with other rules, or can be enabled by configuration.
Use Bind when one let!, do!, or return! site only needs to assign or map the error
of its source. Bind produces a computation-expression marker; a policy is a reusable function that Flow.verify
runs as a workflow step.

