liveBook · Manning

Validation

As explained in F# in Action: A Revised Edition of Get Programming with F#

Validation is the process of checking data against rules that determine whether it is acceptable for a domain or operation.

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

How F# in Action: A Revised Edition of Get Programming with F# covers it

How deep it goes
Works through Result-returning field checks and combination, while deferring all-error accumulation to FsToolkit Validation.
Examples
Uses raw customer and guitar records, plus a dataset parsing and analysis exercise.
What it assumes
Introduces validation from primitive records and standard F# functions without requiring custom converter or annotation frameworks.
What you can do after
Apply it via Result-returning F# functions to convert raw input into trusted domain values and report failures.
How it connects
Connects Result, options, discriminated unions, JSON deserialization, DTOs, and HTTP status codes.

Also explained in

Compare how 30 books explain validation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of F# in Action: A Revised Edition of Get Programming with F#. The section links point to the parts of the book it draws on.