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)