JamesRandall / AccidentalFish.FSharp.Validation

Simple validator DSL / library for F#
MIT License
89 stars 10 forks source link

Chessie.ErrorHandling for ValidationState #1

Open goldfish1974 opened 5 years ago

goldfish1974 commented 5 years ago

Chessie.ErrorHandling provides effectively the same format as your ValidationState but comes with a large number of helpers that can be used to manipulate the Error list.

This differs from the Framework version in that is also has a list of Errors (as well as handling Warn situations too).

Find it here: https://github.com/fsprojects/Chessie

N.B. this was Steffan Forkman and goes with the Railway Oriented Programming topics covered here: https://fsharpforfunandprofit.com/rop/ (Scott Wlaschin) both of which you must have come across.

I'm happy enough to submit a pull request if you like. I'd just use a type for the ValidationState and any helpers from Chessie where appropriate.

JamesRandall commented 5 years ago

Thanks, I'll take a look. I came across Chessie the other day while researching something else funnily enough.

With regard to Warn - any thoughts on how to add that while keeping the syntax super clean? Initially that's why I avoided it (well that and that I didn't need it allowed me to duck it!!).

ROP - yes, but I came across that by way of Kit Eason's book rather than (the excellent and well thumbed by me over the last six months) Fun and Profit.

Thanks for the input :)

JamesRandall commented 5 years ago

Actually... just had a nice idea about Warn. Will take a look later today.

JamesRandall commented 5 years ago

Something like this:

validate (fun r -> r.title) [
    isNotEmpty
    hasMaxLengthOf 128
    warn [
        hasMinLengthOf 32
    ]
]
goldfish1974 commented 5 years ago

Yeah, that looks ok for associating additional info along with the validation.

I'm not sure how it fits in the context of validation though. Perhaps the warn could indicate interdependent fields? If Field1 is valid then Warn other Fields is also flip from optional to required (e.g. Address must have a Postal code or State). I often nest validation in this case though as it means Field1 doesn't have dependencies on other fields.

In your example, above, I can imagine Warn [ passwordWeak ] could be a suitable use.

The warn concept actually fits with Chessie even more closly.

Chessie defines the Result as:

type Result<'TSuccess, 'TMessage> = | Ok of 'TSuccess * 'TMessage list | Bad of 'TMessage list

OK is OK with an empty list, Warn is OK with a list of messages and Bad represents the failure.

There are a bunch of active patterns as well as apply, lift and map type functions in Chessie so that you can compose each of the functions together using |>. At the bottom of the chained functions, you effectively get a list of errors.

I used it heavily in a DSL that I made to create a tree of functions that extract the data from the HTML. The DSL -> Result<FunctionRoot, DSLErrors>. when I run FunctionRoot(HtmlDom) -> Result<Json, ParseErrors>.

The error list that came out was actually a complete list of errors for the whole DSL as well as each of the branches that run when the DSL "program" ran. That way, I didn't have to fix, test, fix etc.

I didn't really have a use for Warn in that case but I felt that Warn is domain specific and the above Chessie Result type for OK having the message list was probably the best fit for Warn (even though I didn't use it).