GitXplorerGitXplorer
c

validity

public
39 stars
3 forks
0 issues

Commits

List of commits on branch master.
Unverified
784632343f6f0d4f4f81265b1e1f47ae1fea718c

Fix travis badge with changes name!

committed 10 years ago
Unverified
231f82d40ef4b0e02c9eab617630699eb33a99c3

Merge pull request #1 from fatih/master

committed 10 years ago
Unverified
8809bc332eb4d13c51ae688b8d056ff2fe01553c

Update fatih/structure to fatih/structs

ffatih committed 10 years ago
Unverified
cc468317e0aac01332135125a0a138c78a137fad

Travis badge

committed 10 years ago
Unverified
7a336e457d57ebc485a90a6e5d91d549d039be9a

Add travis definition

committed 10 years ago
Unverified
906dcca86a64d763f14ad7407897f73ef5e69b29

Fix typo

committed 10 years ago

README

The README file for this repository.

Validity

Build Status

Package to parse and validate unsafe input. Includes a nice range of build-in validators, and is extensible for custom validation rules. This was inspired by Laravel's validators, and was written partially as an experiment while learning Go.

Example

import "validity"

// ...

// Data may be a map[string]interface{}, such as could be returned by JSON decoding.
// Alternately you can validate a struct using the function ValidateStruct
rules := ValidationRules{
    "username": []string{"String", "required", "between:4,30"},
    "email":    []string{"String", "email"}
}

results := ValidateMap(data, rules)

if !results.IsValid {
    fmt.Printf("Error validating data! The following have failed:")
    
    // The following could print output like:
    //
    //  The validator between for username has failed!
    //  The valiator email for email has failed!
    
    for key, failures := range results.Errors {
        for _, method := range failures {
            fmt.Printf("The validator '%s' for '%s' has failed!", method, key);
        }
    }
} else {
    fmt.Print("Data is valid!")
}

Usage

Basic Maps/Structs

ValidationRules, passed into ValidateMap or ValidateStruct, is a map of strings to slices of "things". The keys of the map should be the field names to validate, in the struct or map of input given. The values should be slices of validators to run. For example:

rules := ValidationRules{"username": []string{"String", "required", "between: 4, 30"}}

Tagged Structs

You may also declare your rules as structure tags, in a field validators. Each rule should be seperated by and, like so:

type TestStructTags struct {
	Foo string 	`validators:"between:2,10 and email"`
	Bar int		`validators:"digits:3"`
	Baz float32
}

results := ValidateStructTags(TestStructTags{})

Built-In Rules

... would ensure the "username" is present and between four and 30 characters long. The first element of the map MUST be a value of the type to convert to. Any numeric or string type is valid. If the value cannot be converted to the given type, then it fails validation. The available types are: Int, String, Float.

Possible rules include:

  • accepted: The field under validation must be "yes", "on", true, or 1. Permits numeric and string types.
  • alpha: The field under validation must be entirely alphabetic characters. Permits string types.
  • alpha_dash: The field under validation may have alpha-numeric characters, as well as dashes and underscores. Permits string types.
  • alpha_num: The field under validation must be entirely alpha-numeric characters. Permits string types.
  • between:,a,b: The field under validation must be between "a" and "b" characters long, or between the values a and b (if numeric). Permits string and numeric types.
  • date: The field under validation must parse to a date. Accepts string types.
  • digits:num: The field under validation must have exactly num of digits. Accepts numeric types.
  • digits_between:a,b: The field under validation must have between a and b digits. Accepts numeric types.
  • email: The field under validation must be an email.
  • ip: The field under validation must be an IP, either ipv4 or ipv6. Accepts string types.
  • ipv4: The field under validation must be in IPv4 format. Accepts string types.
  • ipv6: The field under validation must be in IPv6 format. Accepts string types.
  • len:num: The field under validation must be be num characters long. Accepts string types.
  • max: The field under validation must be equal to or shorter than "a" (if a string), or equal to or smaller than "a" (if numeric). Accepts string and numeric types.
  • min: The field under validation must be equal to or longer than "a" (if a string), or equal to or greater than "a" (if numeric). Accepts string and numeric types.
  • regex:pattern: The field under validation must match the given pattern. Accepts string types.
  • required: The field under validation must be present. Accepts any type. Note optionality does not function when trying to validate structs, as it isn't possible to know if their zero values are zero because they aren't set, or because they should actually be zero.
  • url: The field under validation must be a URL. Accepts string types.

The return from the validation functions is a struct ValidationResults:

type ValidationResults struct {
	// Indicates whether the data under validation has passed the set of rules.
	IsValid bool
	// This is a map of strings to slices of strings. Its keys will be any validation fields which had an error, and
	// the values will be the rules which failed.
	Errors  map[string][]string
	// The results is a map of everything after validation. This will be the same data, excluding extraneous values, and
	// values which did not passed validation. They will also be converted to the correct types. Integers will be of
	// type int64, Floats of float64, and Strings of string.
	//
	// The reason that values which did not pass validation are not returned, is because it is not possible to know
	// their types without reflecting them - validation can fail if a value is not able to be converted to a type.
	// This can lead to pitfalls - assuming a value is a of type - not to mention extra work on behalf of the
	// programmer.
	Data map[string]interface{}
}

Custom Validators

There are currently three "types" of validators: IntValidityChecker, FloatValidityChecker, and StringValidityChecker. These contain methods like ValidateRule() bool, and can therefore be extended easily. Let's make a silly validator:

import "validity"

// ...

func (v validity.StringValidityChecker) ValidateSomethingSilly(suffix string) bool {
    return v.Item == "silly" + suffix
}

You can now use the validator like so:

rules := ValidationRules{"someString": []string{"String", "required", "something_silly:String"}}

The validator will now pass only if "someString" is given and is equal to sillyString. You will notice that:

  • "arguments" of the validators get passed in as strings to the function.
  • You do not need a type assertion on v.Item
  • Rules which are in snake_case are converted to StudlyCase automatically.