validationt: Straightforward validation monad

[ bsd3, control, library ] [ Propose Tags ]

A simple data validation library. The main idea is to provide an easy way to validate web form data by aggregating errors for each field.


[Skip to Readme]
Versions [RSS] [faq] 0.1.0.0, 0.1.0.1, 0.2.0.0, 0.2.1.0, 0.3.0
Change log ChangeLog.md
Dependencies aeson (>=1.0), base (>=4.8 && <5), containers, exceptions, lens, monad-control, mtl, QuickCheck, text, transformers, transformers-base, vector [details]
License BSD-3-Clause
Author Typeable.io contributors
Maintainer makeit@typeable.io
Category Control
Home page https://github.com/typeable/validationt
Source repo head: git clone git@github.com:typeable/validationt.git
Uploaded by typeable at 2020-11-03T16:03:57Z
Distributions NixOS:0.3.0
Downloads 2306 total (31 in the last 30 days)
Rating 2.25 (votes: 2) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Hackage Matrix CI
Docs available [build log]
Last success reported on 2020-11-03 [all 1 reports]

Modules

[Index] [Quick Jump]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees

Candidates


Readme for validationt-0.3.0

[back to package description]

Travis CI Badge

ValidationT

A simple data validation library. The main idea is to provide an easy way to validate web form data by aggregating errors for each field.

Usage

Suppose you want to validate some data from the user. Say, that the password adheres to some rules.

You might do something like this:

validatePassword :: Monad m => String -> ValidationT [String] m ()
validatePassword password = do
  vLength password
  vAlpha password
  vNum password
  where
    vLength p = when (length p < 8)
      $ vWarning ["The password should be at least 8 characters long."]
    vAlpha p = unless (any isAlpha p)
      $ vWarning ["The password should contain at least one alphabetic character."]
    vNum p = unless (any isDigit p)
      $ vWarning ["The password should contain at least one numeric character."]

ValidationT e m a essentially just gathers the errors thrown by vWarning.

vWarning :: (Monad m, Monoid e) => e -> ValidationT e m ()

vWarning mappends the given e to the already collected errors. This is why the warnings are contained inside a list.

There is also vError. The only difference between vWarning and vError is that vError stops further execution (and further collection of errors and warnings).

You would use the validation like this:

main :: IO ()
main = do
  password <- getLine
  result <- runValidationTEither . validatePassword $ password
  putStrLn $ case result of
    Left errs -> unlines err
    Right () -> "You are fine."

You could, of course, do more complicated things like use vWarningL and vErrorL to add an error to a mempty structure, which gets mappended with other errors.

The library comes with a MonoidMap newtype wrapper around Map, which mappends the values themselves on conflict. This can be useful if you have a multiple points of failure and you want to distinguich between them -- validating a username and a password for example:

data Piece
  = Password
  | UserName
  deriving (Eq, Show, Ord)

validatePassword :: Monad m => String -> ValidationT (MonoidMap Piece [String]) m ()
validatePassword password = do
  vLength password
  vAlpha password
  vNum password
  where
    warning = mmSingleton UserName
    vLength p = when (length p < 8)
      $ warning ["The password should be at least 8 characters long."]
    vAlpha p = unless (any isAlpha p)
      $ warning ["The password should contain at least one alphabetic character."]
    vNum p = unless (any isDigit p)
      $ warning ["The password should contain at least one numeric character."]

(mmSingleton is a covenience initializer for MonoidMap.)