12

Thoughts On Input Validation Pattern From A Noob

 3 years ago
source link: https://forums.fsharp.org/t/thoughts-on-input-validation-pattern-from-a-noob/1541
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Thoughts On Input Validation Pattern From A Noob

This is very subjective, but I’d like to get some thoughts on this before I put this into practice. On the one hand, I’m proud I got this to compile…but is it too convoluted?

I’m trying to validate user input and:

  • retain valid / remove invalid values from input
  • print a list of all validation errors

Looking at other validation patterns like using applicatives 10, they only give me the error list.

type Input = 
    {name : string option; dob : DateTime option; address : string option}
type InputValid = {name : string; dob : DateTime; address : string}

let errorFun args errors =
    printfn "%O" args //refresh form with only valid args
    errors |> List.iter (fun s -> printfn "%s" s) //print errors up top

let successFun argsV =
    printfn "%O" argsV //do stuff

The idea is to have a validation function that takes the input and returns either an “InputValid” record or the valid part of “Input” * the invalid part in “string list”.

And this is what I came up with:

let inline bindResult f acc =
    match acc with
    | Ok (args, successFun) ->
        match f args with
        | Ok param -> Ok (args, (successFun param))
        | Error (args, ex) -> Error (args, ex)
    | Error (args, ex) ->
        match f args with
        | Ok _ -> Error (args, ex)
        | Error (args, ex') ->
            Error (args, (List.concat [ex'; ex]))

let validateName (args: Input) =
    match args.name with
    | Some n when n.Length > 3 -> Ok n
    | Some _ -> Error ( {args with name = None}, ["no bob and toms allowed"])
    | None -> Error (args, ["name is required"])

let validateDob (args: Input) =
    match args.dob with
    | Some dob when dob > DateTime.Now.AddYears(-12) -> Ok dob
    | Some _ -> Error ({args with dob = None}, ["get off my lawn"])
    | None ->  Error (args, ["dob is required"])

let validateAddress (args: Input) =
    match args.address with
    | Some a -> a |>  Ok
    | None -> Error (args, ["add1 is required"])

let validate (args : Input) =
    let createValid n d a =
        {InputValid.name = n; dob = d ; address = a}
    Ok (args, createValid)
    |> bindResult validateName
    |> bindResult validateDob
    |> bindResult validateAddress
    |> function
    | Ok (_, valid) -> successFun valid
    | Error (args, ex) -> errorFun args ex

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK