Giter Site home page Giter Site logo

validus's Introduction

Validus

NuGet Version Build Status

Validus is a composable validation library for F#, with built-in validators for most primitive types and easily extended through custom validators.

Key Features

Quick Start

A common example of receiving input from an untrusted source (ex: user form submission), applying validation and producing a result based on success/failure.

open Validus
open Validus.Operators

// Untrusted input
type PersonInput = 
      { FirstName : string
        LastName  : string
        Email     : string
        Age       : int option }

// Internal domain model for names
type Name = 
    { First : string
      Last : string }

    static member Create first last = 
      { First = first
        Last = last }

// Internal person record, which has been validated
type Person = 
    { Name  : Name
      Email : string
      Age   : int option }

    static member Create first last email age =
        { Name  = Name.create first last
          Email = email
          Age   = age }   

// PersonInput -> ValidationResult<Person>
let validatePersonInput input = 
    // Shared validator for first & last name
    let nameValidator = 
        Validators.String.betweenLen 3 64 None 

    // Composing multiple validators to form complex validation rules    
    let emailValidator = 
        Validators.String.betweenLen 8 512 None 
        <+> Validators.String.pattern "[^@]+@[^\.]+\..+" (Some (sprintf "Please provide a valid %s")) // Overriding default error message

    // Defining a validator for an optional value, then composing
    // multiple validators to form complex validation rule
    let ageValidator = 
        Validators.optional 
            (Validators.Int.greaterThan 0 None <+> Validators.Int.lessThan 100 None) 
            "Age" 
            expected.Age

    // Construct Person if all validators return Success
    Person.Create
    <!> nameValidator "First name" input.FirstName // <!> is alias for ValidationResult.map
    <*> nameValidator "Last name" input.LastName   // <*> is an alias for ValidationResult.apply
    <*> emailValidator "Email address" input.Email
    <*> Validators.Int.between 1 100 None "Age" input.Age

// Successful execution
let validPersonInput : PersonInput = 
    // ...

let person : ValidationResult<Person> = 
    validatePerson validPersonInput

match person with 
| Success p -> printfn "%A" p
| Failure e -> // ...

// Unsuccessful execution
let invalidPersonInput : PersonInput = 
    // ...

let person : ValidationResult<Person> = 
    validatePerson invalidPersonInput // ValidationResult<Person>

match person with 
| Success p -> // ...
| Failure e -> 
    e 
    |> ValidationErrors.toList
    |> Seq.iter (printfn "%s")  

Built-in Validators

All of the built-in validators reside in the Validators module and follow a similar definition.

// Produce a validation message based on a field name
type ValidationMessage = string -> string

// Produce a validation result based on a field name and result
type Validator<'a> = string -> 'a -> ValidationResult<'a>

// Given 'a value, and optional validtion message produce 
// a ready to use validator for 'a
'a -> ValidationMessage option -> Validator<'a>

Applies to: string, int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

// Define a validator which checks if a string equals
// "foo" displaying the standard error message.
let equalsFoo = 
  Validators.String.equals "foo" None "field"

equalsFoo "bar" // ValidationResult<string>

Applies to: `string, int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

// Define a validator which checks if a string is not 
// equal to "foo" displaying the standard error message.
let notEqualsFoo = 
  Validators.String.equals "foo" None "field"

notEqualsFoo "bar" // ValidationResult<string>

between (inclusive)

Applies to: int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

// Define a validator which checks if an int is between
// 1 and 100 (inclusive) displaying the standard error message.
let between1and100 = 
  Validators.Int.between 1 100 None "field"

between1and100 12 // ValidationResult<int>

Applies to: int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

// Define a validator which checks if an int is greater than
// 100 displaying the standard error message.
let greaterThan100 = 
  Validators.Int.greaterThan 100 None "field"

greaterThan100 12 // ValidationResult<int>

Applies to: int16, int, int64, decimal, float, DateTime, DateTimeOffset, TimeSpan

// Define a validator which checks if an int is less than
// 100 displaying the standard error message.
let lessThan100 = 
  Validators.Int.lessThan 100 None "field"

lessThan100 12 // ValidationResult<int>

String specific validators

Applies to: string

// Define a validator which checks if a string is between
// 1 and 100 chars displaying the standard error message.
let between1and100Chars = 
  Validators.String.betweenLen 1 100 None "field"

between1and100Chars "validus" // ValidationResult<string>

Applies to: string

// Define a validator which checks if a string is greater tha
// 100 chars displaying the standard error message.
let greaterThan100Chars = 
  Validators.String.greaterThanLen 100 None "field"

greaterThan100Chars "validus" // ValidationResult<string>

Applies to: string

// Define a validator which checks if a string is less tha
// 100 chars displaying the standard error message.
let lessThan100Chars = 
  Validators.String.lessThanLen 100 None "field"

lessThan100Chars "validus" // ValidationResult<string>

Applies to: string

// Define a validator which checks if a string is empty
// displaying the standard error message.
let stringIsEmpty = 
  Validators.String.empty None "field"

stringIsEmpty "validus" // ValidationResult<string>

Applies to: string

// Define a validator which checks if a string is not empty
// displaying the standard error message.
let stringIsNotEmpty = 
  Validators.String.notEmpty None "field"

stringIsNotEmpty "validus" // ValidationResult<string>

pattern (Regular Expressions)

Applies to: string

// Define a validator which checks if a string matches the 
// provided regex displaying the standard error message.
let stringIsChars = 
  Validators.String.pattern "[a-z]" None "field"

stringIsChars "validus" // ValidationResult<string>

Custom Validators

Custom validators can be created by combining built-in validators together using Validator.compose, or the <+> infix operator, as well as creating bespoke validator's using Validator.create.

// Combining built-in validators
let emailValidator = 
    Validators.String.betweenLen 8 512 None
    <+> Validators.String.pattern "[^@]+@[^\.]+\..+" None

let email = "[email protected]"
let emailResult = emailValidator "Login email" email 

// Creating a custom validator 
let fooValidator =
    let fooRule : ValidationRule<string> = fun v -> v = "foo"
    let fooMessage = sprintf "%s must be a string that matches 'foo'"
    Validator.create fooMessage fooRule

"bar"
|> fooValidator "Test string" 
// Outputs: [ "Test string", [ "Test string must be a string that matches 'foo'" ] ]

Find a bug?

There's an issue for that.

License

Built with โ™ฅ by Pim Brouwers in Toronto, ON. Licensed under Apache License 2.0.

validus's People

Contributors

bonjune avatar pimbrouwers avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.