git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/validate/README.md (about)

     1  govalidator
     2  ===========
     3  [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/asaskevich/govalidator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![GoDoc](https://godoc.org/github.com/asaskevich/govalidator?status.png)](https://godoc.org/github.com/asaskevich/govalidator)
     4  [![Build Status](https://travis-ci.org/asaskevich/govalidator.svg?branch=master)](https://travis-ci.org/asaskevich/govalidator)
     5  [![Coverage](https://codecov.io/gh/asaskevich/govalidator/branch/master/graph/badge.svg)](https://codecov.io/gh/asaskevich/govalidator) [![Go Report Card](https://goreportcard.com/badge/github.com/asaskevich/govalidator)](https://goreportcard.com/report/github.com/asaskevich/govalidator) [![GoSearch](http://go-search.org/badge?id=github.com%2Fasaskevich%2Fgovalidator)](http://go-search.org/view?id=github.com%2Fasaskevich%2Fgovalidator) [![Backers on Open Collective](https://opencollective.com/govalidator/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/govalidator/sponsors/badge.svg)](#sponsors) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator?ref=badge_shield)
     6  
     7  A package of validators and sanitizers for strings, structs and collections. Based on [validator.js](https://github.com/chriso/validator.js).
     8  
     9  #### Installation
    10  Make sure that Go is installed on your computer.
    11  Type the following command in your terminal:
    12  
    13  	go get github.com/asaskevich/govalidator
    14  
    15  or you can get specified release of the package with `gopkg.in`:
    16  
    17  	go get gopkg.in/asaskevich/govalidator.v10
    18  
    19  After it the package is ready to use.
    20  
    21  
    22  #### Import package in your project
    23  Add following line in your `*.go` file:
    24  ```go
    25  import "github.com/asaskevich/govalidator"
    26  ```
    27  If you are unhappy to use long `govalidator`, you can do something like this:
    28  ```go
    29  import (
    30    valid "github.com/asaskevich/govalidator"
    31  )
    32  ```
    33  
    34  #### Activate behavior to require all fields have a validation tag by default
    35  `SetFieldsRequiredByDefault` causes validation to fail when struct fields do not include validations or are not explicitly marked as exempt (using `valid:"-"` or `valid:"email,optional"`). A good place to activate this is a package init function or the main() function.
    36  
    37  `SetNilPtrAllowedByRequired` causes validation to pass when struct fields marked by `required` are set to nil. This is disabled by default for consistency, but some packages that need to be able to determine between `nil` and `zero value` state can use this. If disabled, both `nil` and `zero` values cause validation errors.
    38  
    39  ```go
    40  import "github.com/asaskevich/govalidator"
    41  
    42  func init() {
    43    govalidator.SetFieldsRequiredByDefault(true)
    44  }
    45  ```
    46  
    47  Here's some code to explain it:
    48  ```go
    49  // this struct definition will fail govalidator.ValidateStruct() (and the field values do not matter):
    50  type exampleStruct struct {
    51    Name  string ``
    52    Email string `valid:"email"`
    53  }
    54  
    55  // this, however, will only fail when Email is empty or an invalid email address:
    56  type exampleStruct2 struct {
    57    Name  string `valid:"-"`
    58    Email string `valid:"email"`
    59  }
    60  
    61  // lastly, this will only fail when Email is an invalid email address but not when it's empty:
    62  type exampleStruct2 struct {
    63    Name  string `valid:"-"`
    64    Email string `valid:"email,optional"`
    65  }
    66  ```
    67  
    68  #### Recent breaking changes (see [#123](https://github.com/asaskevich/govalidator/pull/123))
    69  ##### Custom validator function signature
    70  A context was added as the second parameter, for structs this is the object being validated – this makes dependent validation possible.
    71  ```go
    72  import "github.com/asaskevich/govalidator"
    73  
    74  // old signature
    75  func(i interface{}) bool
    76  
    77  // new signature
    78  func(i interface{}, o interface{}) bool
    79  ```
    80  
    81  ##### Adding a custom validator
    82  This was changed to prevent data races when accessing custom validators.
    83  ```go
    84  import "github.com/asaskevich/govalidator"
    85  
    86  // before
    87  govalidator.CustomTypeTagMap["customByteArrayValidator"] = func(i interface{}, o interface{}) bool {
    88    // ...
    89  }
    90  
    91  // after
    92  govalidator.CustomTypeTagMap.Set("customByteArrayValidator", func(i interface{}, o interface{}) bool {
    93    // ...
    94  })
    95  ```
    96  
    97  #### List of functions:
    98  ```go
    99  func Abs(value float64) float64
   100  func BlackList(str, chars string) string
   101  func ByteLength(str string, params ...string) bool
   102  func CamelCaseToUnderscore(str string) string
   103  func Contains(str, substring string) bool
   104  func Count(array []interface{}, iterator ConditionIterator) int
   105  func Each(array []interface{}, iterator Iterator)
   106  func ErrorByField(e error, field string) string
   107  func ErrorsByField(e error) map[string]string
   108  func Filter(array []interface{}, iterator ConditionIterator) []interface{}
   109  func Find(array []interface{}, iterator ConditionIterator) interface{}
   110  func GetLine(s string, index int) (string, error)
   111  func GetLines(s string) []string
   112  func HasLowerCase(str string) bool
   113  func HasUpperCase(str string) bool
   114  func HasWhitespace(str string) bool
   115  func HasWhitespaceOnly(str string) bool
   116  func InRange(value interface{}, left interface{}, right interface{}) bool
   117  func InRangeFloat32(value, left, right float32) bool
   118  func InRangeFloat64(value, left, right float64) bool
   119  func InRangeInt(value, left, right interface{}) bool
   120  func IsASCII(str string) bool
   121  func IsAlpha(str string) bool
   122  func IsAlphanumeric(str string) bool
   123  func IsBase64(str string) bool
   124  func IsByteLength(str string, min, max int) bool
   125  func IsCIDR(str string) bool
   126  func IsCRC32(str string) bool
   127  func IsCRC32b(str string) bool
   128  func IsCreditCard(str string) bool
   129  func IsDNSName(str string) bool
   130  func IsDataURI(str string) bool
   131  func IsDialString(str string) bool
   132  func IsDivisibleBy(str, num string) bool
   133  func IsEmail(str string) bool
   134  func IsExistingEmail(email string) bool
   135  func IsFilePath(str string) (bool, int)
   136  func IsFloat(str string) bool
   137  func IsFullWidth(str string) bool
   138  func IsHalfWidth(str string) bool
   139  func IsHash(str string, algorithm string) bool
   140  func IsHexadecimal(str string) bool
   141  func IsHexcolor(str string) bool
   142  func IsHost(str string) bool
   143  func IsIP(str string) bool
   144  func IsIPv4(str string) bool
   145  func IsIPv6(str string) bool
   146  func IsISBN(str string, version int) bool
   147  func IsISBN10(str string) bool
   148  func IsISBN13(str string) bool
   149  func IsISO3166Alpha2(str string) bool
   150  func IsISO3166Alpha3(str string) bool
   151  func IsISO4217(str string) bool
   152  func IsISO693Alpha2(str string) bool
   153  func IsISO693Alpha3b(str string) bool
   154  func IsIn(str string, params ...string) bool
   155  func IsInRaw(str string, params ...string) bool
   156  func IsInt(str string) bool
   157  func IsJSON(str string) bool
   158  func IsLatitude(str string) bool
   159  func IsLongitude(str string) bool
   160  func IsLowerCase(str string) bool
   161  func IsMAC(str string) bool
   162  func IsMD4(str string) bool
   163  func IsMD5(str string) bool
   164  func IsMagnetURI(str string) bool
   165  func IsMongoID(str string) bool
   166  func IsMultibyte(str string) bool
   167  func IsNatural(value float64) bool
   168  func IsNegative(value float64) bool
   169  func IsNonNegative(value float64) bool
   170  func IsNonPositive(value float64) bool
   171  func IsNotNull(str string) bool
   172  func IsNull(str string) bool
   173  func IsNumeric(str string) bool
   174  func IsPort(str string) bool
   175  func IsPositive(value float64) bool
   176  func IsPrintableASCII(str string) bool
   177  func IsRFC3339(str string) bool
   178  func IsRFC3339WithoutZone(str string) bool
   179  func IsRGBcolor(str string) bool
   180  func IsRegex(str string) bool
   181  func IsRequestURI(rawurl string) bool
   182  func IsRequestURL(rawurl string) bool
   183  func IsRipeMD128(str string) bool
   184  func IsRipeMD160(str string) bool
   185  func IsRsaPub(str string, params ...string) bool
   186  func IsRsaPublicKey(str string, keylen int) bool
   187  func IsSHA1(str string) bool
   188  func IsSHA256(str string) bool
   189  func IsSHA384(str string) bool
   190  func IsSHA512(str string) bool
   191  func IsSSN(str string) bool
   192  func IsSemver(str string) bool
   193  func IsTiger128(str string) bool
   194  func IsTiger160(str string) bool
   195  func IsTiger192(str string) bool
   196  func IsTime(str string, format string) bool
   197  func IsType(v interface{}, params ...string) bool
   198  func IsURL(str string) bool
   199  func IsUTFDigit(str string) bool
   200  func IsUTFLetter(str string) bool
   201  func IsUTFLetterNumeric(str string) bool
   202  func IsUTFNumeric(str string) bool
   203  func IsUUID(str string) bool
   204  func IsUUIDv3(str string) bool
   205  func IsUUIDv4(str string) bool
   206  func IsUUIDv5(str string) bool
   207  func IsULID(str string) bool
   208  func IsUnixTime(str string) bool
   209  func IsUpperCase(str string) bool
   210  func IsVariableWidth(str string) bool
   211  func IsWhole(value float64) bool
   212  func LeftTrim(str, chars string) string
   213  func Map(array []interface{}, iterator ResultIterator) []interface{}
   214  func Matches(str, pattern string) bool
   215  func MaxStringLength(str string, params ...string) bool
   216  func MinStringLength(str string, params ...string) bool
   217  func NormalizeEmail(str string) (string, error)
   218  func PadBoth(str string, padStr string, padLen int) string
   219  func PadLeft(str string, padStr string, padLen int) string
   220  func PadRight(str string, padStr string, padLen int) string
   221  func PrependPathToErrors(err error, path string) error
   222  func Range(str string, params ...string) bool
   223  func RemoveTags(s string) string
   224  func ReplacePattern(str, pattern, replace string) string
   225  func Reverse(s string) string
   226  func RightTrim(str, chars string) string
   227  func RuneLength(str string, params ...string) bool
   228  func SafeFileName(str string) string
   229  func SetFieldsRequiredByDefault(value bool)
   230  func SetNilPtrAllowedByRequired(value bool)
   231  func Sign(value float64) float64
   232  func StringLength(str string, params ...string) bool
   233  func StringMatches(s string, params ...string) bool
   234  func StripLow(str string, keepNewLines bool) string
   235  func ToBoolean(str string) (bool, error)
   236  func ToFloat(str string) (float64, error)
   237  func ToInt(value interface{}) (res int64, err error)
   238  func ToJSON(obj interface{}) (string, error)
   239  func ToString(obj interface{}) string
   240  func Trim(str, chars string) string
   241  func Truncate(str string, length int, ending string) string
   242  func TruncatingErrorf(str string, args ...interface{}) error
   243  func UnderscoreToCamelCase(s string) string
   244  func ValidateMap(inputMap map[string]interface{}, validationMap map[string]interface{}) (bool, error)
   245  func ValidateStruct(s interface{}) (bool, error)
   246  func WhiteList(str, chars string) string
   247  type ConditionIterator
   248  type CustomTypeValidator
   249  type Error
   250  func (e Error) Error() string
   251  type Errors
   252  func (es Errors) Error() string
   253  func (es Errors) Errors() []error
   254  type ISO3166Entry
   255  type ISO693Entry
   256  type InterfaceParamValidator
   257  type Iterator
   258  type ParamValidator
   259  type ResultIterator
   260  type UnsupportedTypeError
   261  func (e *UnsupportedTypeError) Error() string
   262  type Validator
   263  ```
   264  
   265  #### Examples
   266  ###### IsURL
   267  ```go
   268  println(govalidator.IsURL(`http://user@pass:domain.com/path/page`))
   269  ```
   270  ###### IsType
   271  ```go
   272  println(govalidator.IsType("Bob", "string"))
   273  println(govalidator.IsType(1, "int"))
   274  i := 1
   275  println(govalidator.IsType(&i, "*int"))
   276  ```
   277  
   278  IsType can be used through the tag `type` which is essential for map validation:
   279  ```go
   280  type User	struct {
   281    Name string      `valid:"type(string)"`
   282    Age  int         `valid:"type(int)"`
   283    Meta interface{} `valid:"type(string)"`
   284  }
   285  result, err := govalidator.ValidateStruct(User{"Bob", 20, "meta"})
   286  if err != nil {
   287  	println("error: " + err.Error())
   288  }
   289  println(result)
   290  ```
   291  ###### ToString
   292  ```go
   293  type User struct {
   294  	FirstName string
   295  	LastName string
   296  }
   297  
   298  str := govalidator.ToString(&User{"John", "Juan"})
   299  println(str)
   300  ```
   301  ###### Each, Map, Filter, Count for slices
   302  Each iterates over the slice/array and calls Iterator for every item
   303  ```go
   304  data := []interface{}{1, 2, 3, 4, 5}
   305  var fn govalidator.Iterator = func(value interface{}, index int) {
   306  	println(value.(int))
   307  }
   308  govalidator.Each(data, fn)
   309  ```
   310  ```go
   311  data := []interface{}{1, 2, 3, 4, 5}
   312  var fn govalidator.ResultIterator = func(value interface{}, index int) interface{} {
   313  	return value.(int) * 3
   314  }
   315  _ = govalidator.Map(data, fn) // result = []interface{}{1, 6, 9, 12, 15}
   316  ```
   317  ```go
   318  data := []interface{}{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
   319  var fn govalidator.ConditionIterator = func(value interface{}, index int) bool {
   320  	return value.(int)%2 == 0
   321  }
   322  _ = govalidator.Filter(data, fn) // result = []interface{}{2, 4, 6, 8, 10}
   323  _ = govalidator.Count(data, fn) // result = 5
   324  ```
   325  ###### ValidateStruct [#2](https://github.com/asaskevich/govalidator/pull/2)
   326  If you want to validate structs, you can use tag `valid` for any field in your structure. All validators used with this field in one tag are separated by comma. If you want to skip validation, place `-` in your tag. If you need a validator that is not on the list below, you can add it like this:
   327  ```go
   328  govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool {
   329  	return str == "duck"
   330  })
   331  ```
   332  For completely custom validators (interface-based), see below.
   333  
   334  Here is a list of available validators for struct fields (validator - used function):
   335  ```go
   336  "email":              IsEmail,
   337  "url":                IsURL,
   338  "dialstring":         IsDialString,
   339  "requrl":             IsRequestURL,
   340  "requri":             IsRequestURI,
   341  "alpha":              IsAlpha,
   342  "utfletter":          IsUTFLetter,
   343  "alphanum":           IsAlphanumeric,
   344  "utfletternum":       IsUTFLetterNumeric,
   345  "numeric":            IsNumeric,
   346  "utfnumeric":         IsUTFNumeric,
   347  "utfdigit":           IsUTFDigit,
   348  "hexadecimal":        IsHexadecimal,
   349  "hexcolor":           IsHexcolor,
   350  "rgbcolor":           IsRGBcolor,
   351  "lowercase":          IsLowerCase,
   352  "uppercase":          IsUpperCase,
   353  "int":                IsInt,
   354  "float":              IsFloat,
   355  "null":               IsNull,
   356  "uuid":               IsUUID,
   357  "uuidv3":             IsUUIDv3,
   358  "uuidv4":             IsUUIDv4,
   359  "uuidv5":             IsUUIDv5,
   360  "creditcard":         IsCreditCard,
   361  "isbn10":             IsISBN10,
   362  "isbn13":             IsISBN13,
   363  "json":               IsJSON,
   364  "multibyte":          IsMultibyte,
   365  "ascii":              IsASCII,
   366  "printableascii":     IsPrintableASCII,
   367  "fullwidth":          IsFullWidth,
   368  "halfwidth":          IsHalfWidth,
   369  "variablewidth":      IsVariableWidth,
   370  "base64":             IsBase64,
   371  "datauri":            IsDataURI,
   372  "ip":                 IsIP,
   373  "port":               IsPort,
   374  "ipv4":               IsIPv4,
   375  "ipv6":               IsIPv6,
   376  "dns":                IsDNSName,
   377  "host":               IsHost,
   378  "mac":                IsMAC,
   379  "latitude":           IsLatitude,
   380  "longitude":          IsLongitude,
   381  "ssn":                IsSSN,
   382  "semver":             IsSemver,
   383  "rfc3339":            IsRFC3339,
   384  "rfc3339WithoutZone": IsRFC3339WithoutZone,
   385  "ISO3166Alpha2":      IsISO3166Alpha2,
   386  "ISO3166Alpha3":      IsISO3166Alpha3,
   387  "ulid":               IsULID,
   388  ```
   389  Validators with parameters
   390  
   391  ```go
   392  "range(min|max)": Range,
   393  "length(min|max)": ByteLength,
   394  "runelength(min|max)": RuneLength,
   395  "stringlength(min|max)": StringLength,
   396  "matches(pattern)": StringMatches,
   397  "in(string1|string2|...|stringN)": IsIn,
   398  "rsapub(keylength)" : IsRsaPub,
   399  "minstringlength(int): MinStringLength,
   400  "maxstringlength(int): MaxStringLength,
   401  ```
   402  Validators with parameters for any type
   403  
   404  ```go
   405  "type(type)": IsType,
   406  ```
   407  
   408  And here is small example of usage:
   409  ```go
   410  type Post struct {
   411  	Title    string `valid:"alphanum,required"`
   412  	Message  string `valid:"duck,ascii"`
   413  	Message2 string `valid:"animal(dog)"`
   414  	AuthorIP string `valid:"ipv4"`
   415  	Date     string `valid:"-"`
   416  }
   417  post := &Post{
   418  	Title:   "My Example Post",
   419  	Message: "duck",
   420  	Message2: "dog",
   421  	AuthorIP: "123.234.54.3",
   422  }
   423  
   424  // Add your own struct validation tags
   425  govalidator.TagMap["duck"] = govalidator.Validator(func(str string) bool {
   426  	return str == "duck"
   427  })
   428  
   429  // Add your own struct validation tags with parameter
   430  govalidator.ParamTagMap["animal"] = govalidator.ParamValidator(func(str string, params ...string) bool {
   431      species := params[0]
   432      return str == species
   433  })
   434  govalidator.ParamTagRegexMap["animal"] = regexp.MustCompile("^animal\\((\\w+)\\)$")
   435  
   436  result, err := govalidator.ValidateStruct(post)
   437  if err != nil {
   438  	println("error: " + err.Error())
   439  }
   440  println(result)
   441  ```
   442  ###### ValidateMap [#2](https://github.com/asaskevich/govalidator/pull/338)
   443  If you want to validate maps, you can use the map to be validated and a validation map that contain the same tags used in ValidateStruct, both maps have to be in the form `map[string]interface{}`
   444  
   445  So here is small example of usage:
   446  ```go
   447  var mapTemplate = map[string]interface{}{
   448  	"name":"required,alpha",
   449  	"family":"required,alpha",
   450  	"email":"required,email",
   451  	"cell-phone":"numeric",
   452  	"address":map[string]interface{}{
   453  		"line1":"required,alphanum",
   454  		"line2":"alphanum",
   455  		"postal-code":"numeric",
   456  	},
   457  }
   458  
   459  var inputMap = map[string]interface{}{
   460  	"name":"Bob",
   461  	"family":"Smith",
   462  	"email":"foo@bar.baz",
   463  	"address":map[string]interface{}{
   464  		"line1":"",
   465  		"line2":"",
   466  		"postal-code":"",
   467  	},
   468  }
   469  
   470  result, err := govalidator.ValidateMap(inputMap, mapTemplate)
   471  if err != nil {
   472  	println("error: " + err.Error())
   473  }
   474  println(result)
   475  ```
   476  
   477  ###### WhiteList
   478  ```go
   479  // Remove all characters from string ignoring characters between "a" and "z"
   480  println(govalidator.WhiteList("a3a43a5a4a3a2a23a4a5a4a3a4", "a-z") == "aaaaaaaaaaaa")
   481  ```
   482  
   483  ###### Custom validation functions
   484  Custom validation using your own domain specific validators is also available - here's an example of how to use it:
   485  ```go
   486  import "github.com/asaskevich/govalidator"
   487  
   488  type CustomByteArray [6]byte // custom types are supported and can be validated
   489  
   490  type StructWithCustomByteArray struct {
   491    ID              CustomByteArray `valid:"customByteArrayValidator,customMinLengthValidator"` // multiple custom validators are possible as well and will be evaluated in sequence
   492    Email           string          `valid:"email"`
   493    CustomMinLength int             `valid:"-"`
   494  }
   495  
   496  govalidator.CustomTypeTagMap.Set("customByteArrayValidator", func(i interface{}, context interface{}) bool {
   497    switch v := context.(type) { // you can type switch on the context interface being validated
   498    case StructWithCustomByteArray:
   499      // you can check and validate against some other field in the context,
   500      // return early or not validate against the context at all – your choice
   501    case SomeOtherType:
   502      // ...
   503    default:
   504      // expecting some other type? Throw/panic here or continue
   505    }
   506  
   507    switch v := i.(type) { // type switch on the struct field being validated
   508    case CustomByteArray:
   509      for _, e := range v { // this validator checks that the byte array is not empty, i.e. not all zeroes
   510        if e != 0 {
   511          return true
   512        }
   513      }
   514    }
   515    return false
   516  })
   517  govalidator.CustomTypeTagMap.Set("customMinLengthValidator", func(i interface{}, context interface{}) bool {
   518    switch v := context.(type) { // this validates a field against the value in another field, i.e. dependent validation
   519    case StructWithCustomByteArray:
   520      return len(v.ID) >= v.CustomMinLength
   521    }
   522    return false
   523  })
   524  ```
   525  
   526  ###### Loop over Error()
   527  By default .Error() returns all errors in a single String. To access each error you can do this:
   528  ```go
   529    if err != nil {
   530      errs := err.(govalidator.Errors).Errors()
   531      for _, e := range errs {
   532        fmt.Println(e.Error())
   533      }
   534    }
   535  ```
   536  
   537  ###### Custom error messages
   538  Custom error messages are supported via annotations by adding the `~` separator - here's an example of how to use it:
   539  ```go
   540  type Ticket struct {
   541    Id        int64     `json:"id"`
   542    FirstName string    `json:"firstname" valid:"required~First name is blank"`
   543  }
   544  ```
   545  
   546  #### Notes
   547  Documentation is available here: [godoc.org](https://godoc.org/github.com/asaskevich/govalidator).
   548  Full information about code coverage is also available here: [govalidator on gocover.io](http://gocover.io/github.com/asaskevich/govalidator).
   549  
   550  #### Support
   551  If you do have a contribution to the package, feel free to create a Pull Request or an Issue.
   552  
   553  #### What to contribute
   554  If you don't know what to do, there are some features and functions that need to be done
   555  
   556  - [ ] Refactor code
   557  - [ ] Edit docs and [README](https://github.com/asaskevich/govalidator/README.md): spellcheck, grammar and typo check
   558  - [ ] Create actual list of contributors and projects that currently using this package
   559  - [ ] Resolve [issues and bugs](https://github.com/asaskevich/govalidator/issues)
   560  - [ ] Update actual [list of functions](https://github.com/asaskevich/govalidator#list-of-functions)
   561  - [ ] Update [list of validators](https://github.com/asaskevich/govalidator#validatestruct-2) that available for `ValidateStruct` and add new
   562  - [ ] Implement new validators: `IsFQDN`, `IsIMEI`, `IsPostalCode`, `IsISIN`, `IsISRC` etc
   563  - [x] Implement [validation by maps](https://github.com/asaskevich/govalidator/issues/224)
   564  - [ ] Implement fuzzing testing
   565  - [ ] Implement some struct/map/array utilities
   566  - [ ] Implement map/array validation
   567  - [ ] Implement benchmarking
   568  - [ ] Implement batch of examples
   569  - [ ] Look at forks for new features and fixes
   570  
   571  #### Advice
   572  Feel free to create what you want, but keep in mind when you implement new features:
   573  - Code must be clear and readable, names of variables/constants clearly describes what they are doing
   574  - Public functions must be documented and described in source file and added to README.md to the list of available functions
   575  - There are must be unit-tests for any new functions and improvements
   576  
   577  ## Credits
   578  ### Contributors
   579  
   580  This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
   581  
   582  #### Special thanks to [contributors](https://github.com/asaskevich/govalidator/graphs/contributors)
   583  * [Daniel Lohse](https://github.com/annismckenzie)
   584  * [Attila Oláh](https://github.com/attilaolah)
   585  * [Daniel Korner](https://github.com/Dadie)
   586  * [Steven Wilkin](https://github.com/stevenwilkin)
   587  * [Deiwin Sarjas](https://github.com/deiwin)
   588  * [Noah Shibley](https://github.com/slugmobile)
   589  * [Nathan Davies](https://github.com/nathj07)
   590  * [Matt Sanford](https://github.com/mzsanford)
   591  * [Simon ccl1115](https://github.com/ccl1115)
   592  
   593  <a href="https://github.com/asaskevich/govalidator/graphs/contributors"><img src="https://opencollective.com/govalidator/contributors.svg?width=890" /></a>
   594  
   595  
   596  ### Backers
   597  
   598  Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/govalidator#backer)]
   599  
   600  <a href="https://opencollective.com/govalidator#backers" target="_blank"><img src="https://opencollective.com/govalidator/backers.svg?width=890"></a>
   601  
   602  
   603  ### Sponsors
   604  
   605  Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/govalidator#sponsor)]
   606  
   607  <a href="https://opencollective.com/govalidator/sponsor/0/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/0/avatar.svg"></a>
   608  <a href="https://opencollective.com/govalidator/sponsor/1/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/1/avatar.svg"></a>
   609  <a href="https://opencollective.com/govalidator/sponsor/2/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/2/avatar.svg"></a>
   610  <a href="https://opencollective.com/govalidator/sponsor/3/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/3/avatar.svg"></a>
   611  <a href="https://opencollective.com/govalidator/sponsor/4/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/4/avatar.svg"></a>
   612  <a href="https://opencollective.com/govalidator/sponsor/5/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/5/avatar.svg"></a>
   613  <a href="https://opencollective.com/govalidator/sponsor/6/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/6/avatar.svg"></a>
   614  <a href="https://opencollective.com/govalidator/sponsor/7/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/7/avatar.svg"></a>
   615  <a href="https://opencollective.com/govalidator/sponsor/8/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/8/avatar.svg"></a>
   616  <a href="https://opencollective.com/govalidator/sponsor/9/website" target="_blank"><img src="https://opencollective.com/govalidator/sponsor/9/avatar.svg"></a>
   617  
   618  
   619  
   620  
   621  ## License
   622  [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fasaskevich%2Fgovalidator?ref=badge_large)