Validation checks raw input against domain rules before the application treats it as trusted data. Rather than returning only a Boolean or an option, return a Result so success carries a rich domain value and failure carries a useful message. Using the validated type downstream makes conversion from raw data an explicit boundary. section 9.2 section 9.2.1
Model external JSON or HTTP input as a simple record of primitive values, then map it with ordinary F# functions into a richer model. Keep domain rules out of JSON converters and attribute-heavy validation frameworks; reusable composable functions remain flexible as rules grow. section 10.2.1 section 13.2.7
A practical validation flow is:
- Deserialize or receive a raw record that closely matches the incoming shape. section 10.2.1
- Validate each field, returning Ok for a valid domain value or Error with a specific message. section 9.2.1
- Combine successful values into the rich domain model; propagate an error otherwise. section 9.2.1
- At an HTTP boundary, turn validation errors into a 4xx response and successful values into application handling. section 13.2.7
Validate a customer identifier and country
A raw customer can require an ID beginning with "C" and convert "USA" to Domestic, other nonempty countries to Foreign. Each conversion returns Ok with its domain value or Error with a precise reason; only two Ok values permit construction of Customer. section 9.2.1
Listing 9.2 Using results instead of options for validation
let validateCustomer (rawCustomer:RawCustomer) =
let customerId =
if rawCustomer.CustomerId.StartsWith "C" then
Ok (CustomerId(int rawCustomer.CustomerId[1..])) #1
else
Error $"Invalid Customer Id '{rawCustomer.CustomerId}'." #2
let country =
match rawCustomer.Country with
| "" -> Error "No country supplied" #2
| "USA" -> Ok Domestic #1
| other -> Ok (Foreign other) #1
match customerId, country with
| Ok customerId, Ok country -> #3
Ok ... // body omitted for clarity
| Error err, _ #4
| _, Error err ->
Error err
Inspect a small Result-based validator that checks two raw fields, preserves a specific error, and constructs a value only when both checks succeed. section 9.2.1





























