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.JavaScriptConfiguration read from the environment is the classic source of a late, confusing startup failure: a missing
variable surfaces as a null, and a malformed one as a parse exception somewhere further in. Axial.PlatformService
splits this into two modules — one for raw access, one for typed reads with a failure channel.
open System
open Axial
open Axial.PlatformService
SystemAxialPlatformServiceEnvironmentVariables returns what is there, with no opinion about what is required:
EnvironmentVariables.tryGet name // string option
EnvironmentVariables.getAll // IReadOnlyDictionary<string, string>
EnvironmentVariables.set name value
EnvironmentVariables.clear name
EnvironmentVariables.expand text // expands %VAR% referencesTyped reads
EnvironmentVariable reads a variable, requires it, and parses it, failing with EnvironmentVariableError:
let readPort : Flow<BaseRuntime, EnvironmentVariableError, int> =
EnvironmentVariable.getInt "PORT"
readPort: Flow<BaseRuntime,EnvironmentVariableError,int>Axial.Flow`3Represents a cold workflow that reads an environment, returns a typed result, and is executed explicitly through one of its execution members such as ToTask, ToAsync, or RunSynchronously. The type of the environment dependency. The type of the failure value. The type of the success value.
Axial.PlatformService.BaseRuntimeGroups the standard operational services commonly used by workflow hosts.
Axial.PlatformService.EnvironmentVariableErrorintAn abbreviation for the CLI type . Basic Types
Axial.PlatformService.EnvironmentVariableHelpers for reading and parsing environment variables through an explicit service.
getInt: string -> Flow<'env,EnvironmentVariableError,int>Reads an integer environment variable through an explicit service.
Adding a parameter removes the restriction, because a function can be. A unit parameter is enough, and the result
stays usable in any environment supplying the service:
let readPortIn () : Flow<#IHasEnvironmentVariables, EnvironmentVariableError, int> =
EnvironmentVariable.getInt "PORT"
readPortIn: unit -> Flow<'a,EnvironmentVariableError,int>Axial.Flow`3Represents a cold workflow that reads an environment, returns a typed result, and is executed explicitly through one of its execution members such as ToTask, ToAsync, or RunSynchronously. The type of the environment dependency. The type of the failure value. The type of the success value.
Axial.PlatformService.IHasEnvironmentVariablesDeclares that an environment supplies the environment-variable service.
Axial.PlatformService.EnvironmentVariableErrorintAn abbreviation for the CLI type . Basic Types
Axial.PlatformService.EnvironmentVariableHelpers for reading and parsing environment variables through an explicit service.
getInt: string -> Flow<'env,EnvironmentVariableError,int>Reads an integer environment variable through an explicit service.
| Function | Result |
|---|---|
get |
string, failing when absent |
tryGet |
string option, never failing |
getInt, getInt64 |
Integers |
getDouble, getDecimal |
Numbers |
getBool |
Booleans |
getGuid |
GUIDs |
getUri |
URIs |
getTimeSpan |
Durations |
Numeric parsing uses the invariant culture, so a variable set on a machine with a comma decimal separator reads the same everywhere.
EnvironmentVariableError has two cases, and they carry enough to write a useful message:
MissingVariable name— the variable was not set.InvalidVariable (name, value, expected)— it was set but did not parse, with what was expected.
EnvironmentVariableErrors.describe formats either into a sentence such as Environment variable 'PORT' had value 'eighty' but expected an integer.
Failing startup once, with everything wrong listed
Because the reads are flows with a typed error, configuration validation composes into one workflow that either produces the settings record or reports what is wrong:
let readSettings =
flow {
let! port = EnvironmentVariable.getInt "PORT"
let! endpoint = EnvironmentVariable.getUri "API_ENDPOINT"
let! timeout = EnvironmentVariable.getTimeSpan "API_TIMEOUT"
return { Port = port; Endpoint = endpoint; Timeout = timeout }
}Supplying the service
EnvironmentVariables.live reads the current process environment. EnvironmentVariables.fromPairs builds a fixed
provider, which is how tests avoid mutating global process state:
let environment =
EnvironmentVariables.fromPairs
[ "PORT", "8080"
"API_ENDPOINT", "https://api.example.com" ]
environment: IEnvironmentVariablesAxial.PlatformService.EnvironmentVariablesHelpers for the environment-variable service.
fromPairs: (string * string) seq -> IEnvironmentVariablesCreates a deterministic provider from a fixed set of name/value pairs.

