Showing preview only (2,099K chars total). Download the full file or copy to clipboard to get everything.
Repository: go-playground/validator
Branch: master
Commit: 7fa95998a0d9
Files: 94
Total size: 2.0 MB
Directory structure:
gitextract_ki70tqza/
├── .github/
│ ├── CODEOWNERS
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ └── bug_report.yml
│ ├── PULL_REQUEST_TEMPLATE.md
│ ├── dependabot.yml
│ └── workflows/
│ └── workflow.yml
├── .gitignore
├── .golangci.yaml
├── LICENSE
├── MAINTAINERS.md
├── Makefile
├── README.md
├── _examples/
│ ├── custom/
│ │ └── main.go
│ ├── custom-validation/
│ │ └── main.go
│ ├── dive/
│ │ └── main.go
│ ├── gin-upgrading-overriding/
│ │ ├── main.go
│ │ └── v8_to_v9.go
│ ├── http-transalations/
│ │ └── main.go
│ ├── map-validation/
│ │ └── main.go
│ ├── simple/
│ │ └── main.go
│ ├── struct-level/
│ │ └── main.go
│ ├── struct-map-rules-validation/
│ │ └── main.go
│ ├── translations/
│ │ └── main.go
│ ├── validate_fn/
│ │ ├── enum_enumer.go
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── main.go
│ └── valuer/
│ └── main.go
├── baked_in.go
├── benchmarks_test.go
├── cache.go
├── country_codes.go
├── currency_codes.go
├── doc.go
├── errors.go
├── field_level.go
├── go.mod
├── go.sum
├── non-standard/
│ └── validators/
│ ├── notblank.go
│ └── notblank_test.go
├── options.go
├── postcode_regexes.go
├── regexes.go
├── struct_level.go
├── testdata/
│ └── a.go
├── translations/
│ ├── ar/
│ │ ├── ar.go
│ │ └── ar_test.go
│ ├── de/
│ │ ├── de.go
│ │ └── de_test.go
│ ├── en/
│ │ ├── en.go
│ │ └── en_test.go
│ ├── es/
│ │ ├── es.go
│ │ └── es_test.go
│ ├── fa/
│ │ ├── fa.go
│ │ └── fa_test.go
│ ├── fr/
│ │ ├── fr.go
│ │ └── fr_test.go
│ ├── id/
│ │ ├── id.go
│ │ └── id_test.go
│ ├── it/
│ │ ├── it.go
│ │ └── it_test.go
│ ├── ja/
│ │ ├── ja.go
│ │ └── ja_test.go
│ ├── ko/
│ │ ├── ko.go
│ │ └── ko_test.go
│ ├── lv/
│ │ ├── lv.go
│ │ └── lv_test.go
│ ├── nl/
│ │ ├── nl.go
│ │ └── nl_test.go
│ ├── pl/
│ │ ├── pl.go
│ │ └── pl_test.go
│ ├── pt/
│ │ ├── pt.go
│ │ └── pt_test.go
│ ├── pt_BR/
│ │ ├── pt_BR.go
│ │ └── pt_BR_test.go
│ ├── ru/
│ │ ├── ru.go
│ │ └── ru_test.go
│ ├── th/
│ │ ├── th.go
│ │ └── th_test.go
│ ├── tr/
│ │ ├── tr.go
│ │ └── tr_test.go
│ ├── uk/
│ │ ├── uk.go
│ │ └── uk_test.go
│ ├── vi/
│ │ ├── vi.go
│ │ └── vi_test.go
│ ├── zh/
│ │ ├── zh.go
│ │ └── zh_test.go
│ └── zh_tw/
│ ├── zh_tw.go
│ └── zh_tw_test.go
├── translations.go
├── util.go
├── validator.go
├── validator_instance.go
└── validator_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/CODEOWNERS
================================================
* @go-playground/validator-maintainers
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contribution Guidelines
## Quality Standard
To ensure the continued stability of this package, tests are required that cover the change in order for a pull request to be merged.
## Reporting issues
Please open an issue or join the gitter chat [](https://gitter.im/go-playground/validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) for any issues, questions or possible enhancements to the package.
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: Bug Report
description: File a bug report
title: "[Bug]: "
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of validator are you running?
validations:
required: true
- type: textarea
id: code
attributes:
label: Example Code
description: Please provide a code example that demonstrates the issue
render: go
validations:
required: true
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## Fixes Or Enhances
**Make sure that you've checked the boxes below before you submit PR:**
- [ ] Tests exist or have been written that cover this particular change.
@go-playground/validator-maintainers
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
# Maintain dependencies for Golang
- package-ecosystem: gomod
directory: "/"
schedule:
interval: weekly
# Maintain dependencies for GitHub Actions
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
================================================
FILE: .github/workflows/workflow.yml
================================================
on:
push:
branches:
- master
pull_request:
name: Test
jobs:
test:
strategy:
matrix:
go-version: [1.25.x, 1.26.x]
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Install Go
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go-version }}
- name: Test
run: go test -race -covermode=atomic -coverprofile="profile.cov" ./...
- name: Send Coverage
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.24.x'
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: profile.cov
golangci:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-go@v6
with:
go-version: 1.25.x
- name: golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: latest
================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
bin
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
*.test
*.out
*.txt
/**/*.DS_Store
cover.html
README.html
.idea
================================================
FILE: .golangci.yaml
================================================
version: "2"
linters:
default: all
disable:
- noinlineerr
- wsl_v5
- copyloopvar
- cyclop
- depguard
- dogsled
- dupl
- dupword
- err113
- errorlint
- exhaustive
- exhaustruct
- forbidigo
- forcetypeassert
- funlen
- gochecknoglobals
- gocognit
- goconst
- gocritic
- gocyclo
- godot
- gosec
- gosmopolitan
- interfacebloat
- intrange
- ireturn
- lll
- maintidx
- misspell
- mnd
- modernize
- nakedret
- nestif
- nilnil
- nlreturn
- nonamedreturns
- paralleltest
- perfsprint
- prealloc
- recvcheck
- revive
- staticcheck
- tagalign
- tagliatelle
- testpackage
- thelper
- tparallel
- unparam
- varnamelen
- wrapcheck
- wsl
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2015 Dean Karn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MAINTAINERS.md
================================================
## Maintainers Guide
### Semantic Versioning
Semantic versioning as defined [here](https://semver.org) must be strictly adhered to.
### External Dependencies
Any new external dependencies MUST:
- Have a compatible LICENSE present.
- Be actively maintained.
- Be approved by @go-playground/admins
### PR Merge Requirements
- Up-to-date branch.
- Passing tests and linting.
- CODEOWNERS approval.
- Tests that cover both the Happy and Unhappy paths.
================================================
FILE: Makefile
================================================
GOCMD=go
linters-install:
@golangci-lint --version >/dev/null 2>&1 || { \
echo "installing linting tools..."; \
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s v2.0.2; \
}
lint: linters-install
golangci-lint run
test:
$(GOCMD) test -cover -race ./...
bench:
$(GOCMD) test -run=NONE -bench=. -benchmem ./...
.PHONY: test lint linters-install
================================================
FILE: README.md
================================================
Package validator
=================
<img align="right" src="logo.png">[](https://github.com/go-playground/validator/releases)
[](https://github.com/go-playground/validator/actions)
[](https://coveralls.io/github/go-playground/validator?branch=master)
[](https://goreportcard.com/report/github.com/go-playground/validator)
[](https://pkg.go.dev/github.com/go-playground/validator/v10)

Package validator implements value validations for structs and individual fields based on tags.
It has the following **unique** features:
- Cross Field and Cross Struct validations by using validation tags or custom validators.
- Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated.
- Ability to dive into both map keys and values for validation
- Handles type interface by determining it's underlying type prior to validation.
- Handles custom field types such as sql driver [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) and the [Valuer interface](https://github.com/go-playground/validator/blob/master/_examples/valuer/main.go)
- Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs
- Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError
- Customizable i18n aware error messages.
- Default validator for the [gin](https://github.com/gin-gonic/gin) web framework; upgrading from v8 to v9 in gin see [here](https://github.com/go-playground/validator/tree/master/_examples/gin-upgrading-overriding)
A Call for Maintainers
----------------------
Please read the discussion started [here](https://github.com/go-playground/validator/discussions/1330) if you are interested in contributing/helping maintain this package.
Installation
------------
Use go get.
go get github.com/go-playground/validator/v10
Then import the validator package into your own code.
import "github.com/go-playground/validator/v10"
Error Return Value
-------
Validation functions return type error
They return type error to avoid the issue discussed in the following, where err is always != nil:
* http://stackoverflow.com/a/29138676/3158232
* https://github.com/go-playground/validator/issues/134
Validator returns only InvalidValidationError for bad validation input, nil or ValidationErrors as type error; so, in your code all you need to do is check if the error returned is not nil, and if it's not check if error is InvalidValidationError ( if necessary, most of the time it isn't ) type cast it to type ValidationErrors like so:
```go
err := validate.Struct(mystruct)
validationErrors := err.(validator.ValidationErrors)
```
Usage and documentation
------
Please see https://pkg.go.dev/github.com/go-playground/validator/v10 for detailed usage docs.
##### Examples:
- [Simple](https://github.com/go-playground/validator/blob/master/_examples/simple/main.go)
- [Custom Field Types](https://github.com/go-playground/validator/blob/master/_examples/custom/main.go)
- [Struct Level](https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go)
- [Translations & Custom Errors](https://github.com/go-playground/validator/blob/master/_examples/translations/main.go)
- [Gin upgrade and/or override validator](https://github.com/go-playground/validator/tree/v9/_examples/gin-upgrading-overriding)
- [wash - an example application putting it all together](https://github.com/bluesuncorp/wash)
Baked-in Validations
------
### Special Notes:
- If new to using validator it is highly recommended to initialize it using the `WithRequiredStructEnabled` option which is opt-in to new behaviour that will become the default behaviour in v11+. See documentation for more details.
```go
validate := validator.New(validator.WithRequiredStructEnabled())
```
### Fields:
| Tag | Description |
| - | - |
| eqcsfield | Field Equals Another Field (relative)|
| eqfield | Field Equals Another Field |
| fieldcontains | Check the indicated characters are present in the Field |
| fieldexcludes | Check the indicated characters are not present in the field |
| gtcsfield | Field Greater Than Another Relative Field |
| gtecsfield | Field Greater Than or Equal To Another Relative Field |
| gtefield | Field Greater Than or Equal To Another Field |
| gtfield | Field Greater Than Another Field |
| ltcsfield | Less Than Another Relative Field |
| ltecsfield | Less Than or Equal To Another Relative Field |
| ltefield | Less Than or Equal To Another Field |
| ltfield | Less Than Another Field |
| necsfield | Field Does Not Equal Another Field (relative) |
| nefield | Field Does Not Equal Another Field |
### Network:
| Tag | Description |
| - | - |
| cidr | Classless Inter-Domain Routing CIDR |
| cidrv4 | Classless Inter-Domain Routing CIDRv4 |
| cidrv6 | Classless Inter-Domain Routing CIDRv6 |
| datauri | Data URL |
| fqdn | Full Qualified Domain Name (FQDN) |
| hostname | Hostname RFC 952 |
| hostname_rfc1123 | Hostname RFC 1123 |
| hostname_port | HostPort |
| port | Port number |
| ip | Internet Protocol Address IP |
| ip4_addr | Internet Protocol Address IPv4 |
| ip6_addr | Internet Protocol Address IPv6 |
| ip_addr | Internet Protocol Address IP |
| ipv4 | Internet Protocol Address IPv4 |
| ipv6 | Internet Protocol Address IPv6 |
| mac | Media Access Control Address MAC |
| tcp4_addr | Transmission Control Protocol Address TCPv4 |
| tcp6_addr | Transmission Control Protocol Address TCPv6 |
| tcp_addr | Transmission Control Protocol Address TCP |
| udp4_addr | User Datagram Protocol Address UDPv4 |
| udp6_addr | User Datagram Protocol Address UDPv6 |
| udp_addr | User Datagram Protocol Address UDP |
| unix_addr | Unix domain socket end point Address |
| uds_exists | Unix domain socket exists (checks filesystem sockets and Linux abstract sockets) |
| uri | URI String |
| url | URL String |
| http_url | HTTP(s) URL String |
| https_url | HTTPS-only URL String |
| url_encoded | URL Encoded |
| urn_rfc2141 | Urn RFC 2141 String |
### Strings:
| Tag | Description |
| - | - |
| alpha | Alpha Only |
| alphaspace | Alpha Space |
| alphanum | Alphanumeric |
| alphanumspace | Alphanumeric Space |
| alphanumunicode | Alphanumeric Unicode |
| alphaunicode | Alpha Unicode |
| ascii | ASCII |
| boolean | Boolean |
| contains | Contains |
| containsany | Contains Any |
| containsrune | Contains Rune |
| endsnotwith | Ends Not With |
| endswith | Ends With |
| excludes | Excludes |
| excludesall | Excludes All |
| excludesrune | Excludes Rune |
| lowercase | Lowercase |
| multibyte | Multi-Byte Characters |
| number | Number |
| numeric | Numeric |
| printascii | Printable ASCII |
| startsnotwith | Starts Not With |
| startswith | Starts With |
| uppercase | Uppercase |
### Format:
| Tag | Description |
| - | - |
| base64 | Base64 String |
| base64url | Base64URL String |
| base64rawurl | Base64RawURL String |
| bic_iso_9362_2014 | Business Identifier Code (ISO 9362:2014) |
| bic | Business Identifier Code (ISO 9362:2022) |
| bcp47_language_tag | Language tag (BCP 47) |
| btc_addr | Bitcoin Address |
| btc_addr_bech32 | Bitcoin Bech32 Address (segwit) |
| credit_card | Credit Card Number |
| mongodb | MongoDB ObjectID |
| mongodb_connection_string | MongoDB Connection String |
| cron | Cron |
| spicedb | SpiceDb ObjectID/Permission/Type |
| datetime | Datetime |
| e164 | e164 formatted phone number |
| ein | U.S. Employer Identification Number |
| email | E-mail String
| eth_addr | Ethereum Address |
| hexadecimal | Hexadecimal String |
| hexcolor | Hexcolor String |
| hsl | HSL String |
| hsla | HSLA String |
| cmyk | CMYK String |
| html | HTML Tags |
| html_encoded | HTML Encoded |
| isbn | International Standard Book Number |
| isbn10 | International Standard Book Number 10 |
| isbn13 | International Standard Book Number 13 |
| issn | International Standard Serial Number |
| iso3166_1_alpha2 | Two-letter country code (ISO 3166-1 alpha-2) |
| iso3166_1_alpha3 | Three-letter country code (ISO 3166-1 alpha-3) |
| iso3166_1_alpha_numeric | Numeric country code (ISO 3166-1 numeric) |
| iso3166_2 | Country subdivision code (ISO 3166-2) |
| iso4217 | Currency code (ISO 4217) |
| json | JSON |
| jwt | JSON Web Token (JWT) |
| latitude | Latitude |
| longitude | Longitude |
| luhn_checksum | Luhn Algorithm Checksum (for strings and (u)int) |
| postcode_iso3166_alpha2 | Postcode |
| postcode_iso3166_alpha2_field | Postcode |
| rgb | RGB String |
| rgba | RGBA String |
| ssn | Social Security Number SSN |
| timezone | Timezone |
| uuid | Universally Unique Identifier UUID |
| uuid3 | Universally Unique Identifier UUID v3 |
| uuid3_rfc4122 | Universally Unique Identifier UUID v3 RFC4122 |
| uuid4 | Universally Unique Identifier UUID v4 |
| uuid4_rfc4122 | Universally Unique Identifier UUID v4 RFC4122 |
| uuid5 | Universally Unique Identifier UUID v5 |
| uuid5_rfc4122 | Universally Unique Identifier UUID v5 RFC4122 |
| uuid_rfc4122 | Universally Unique Identifier UUID RFC4122 |
| md4 | MD4 hash |
| md5 | MD5 hash |
| sha256 | SHA256 hash |
| sha384 | SHA384 hash |
| sha512 | SHA512 hash |
| ripemd128 | RIPEMD-128 hash |
| ripemd128 | RIPEMD-160 hash |
| tiger128 | TIGER128 hash |
| tiger160 | TIGER160 hash |
| tiger192 | TIGER192 hash |
| semver | Semantic Versioning 2.0.0 |
| ulid | Universally Unique Lexicographically Sortable Identifier ULID |
| cve | Common Vulnerabilities and Exposures Identifier (CVE id) |
### Comparisons:
| Tag | Description |
| - | - |
| eq | Equals |
| eq_ignore_case | Equals ignoring case |
| gt | Greater than|
| gte | Greater than or equal |
| lt | Less Than |
| lte | Less Than or Equal |
| ne | Not Equal |
| ne_ignore_case | Not Equal ignoring case |
### Other:
| Tag | Description |
| - | - |
| dir | Existing Directory |
| dirpath | Directory Path |
| file | Existing File |
| filepath | File Path |
| image | Image |
| isdefault | Is Default |
| len | Length |
| max | Maximum |
| min | Minimum |
| oneof | One Of |
| required | Required |
| required_if | Required If |
| required_unless | Required Unless |
| required_with | Required With |
| required_with_all | Required With All |
| required_without | Required Without |
| required_without_all | Required Without All |
| excluded_if | Excluded If |
| excluded_unless | Excluded Unless |
| excluded_with | Excluded With |
| excluded_with_all | Excluded With All |
| excluded_without | Excluded Without |
| excluded_without_all | Excluded Without All |
| unique | Unique |
| validateFn | Verify if the method `Validate() error` does not return an error (or any specified method) |
#### Aliases:
| Tag | Description |
| - | - |
| iscolor | hexcolor\|rgb\|rgba\|hsl\|hsla\|cmyk |
| country_code | iso3166_1_alpha2\|iso3166_1_alpha3\|iso3166_1_alpha_numeric |
Benchmarks
------
###### Run on MacBook Pro Max M3
```go
go version go1.23.3 darwin/arm64
goos: darwin
goarch: arm64
cpu: Apple M3 Max
pkg: github.com/go-playground/validator/v10
BenchmarkFieldSuccess-16 42461943 27.88 ns/op 0 B/op 0 allocs/op
BenchmarkFieldSuccessParallel-16 486632887 2.289 ns/op 0 B/op 0 allocs/op
BenchmarkFieldFailure-16 9566167 121.3 ns/op 200 B/op 4 allocs/op
BenchmarkFieldFailureParallel-16 17551471 83.68 ns/op 200 B/op 4 allocs/op
BenchmarkFieldArrayDiveSuccess-16 7602306 155.6 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveSuccessParallel-16 20664610 59.80 ns/op 97 B/op 5 allocs/op
BenchmarkFieldArrayDiveFailure-16 4659756 252.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldArrayDiveFailureParallel-16 8010116 152.9 ns/op 301 B/op 10 allocs/op
BenchmarkFieldMapDiveSuccess-16 2834575 421.2 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveSuccessParallel-16 7179700 171.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveFailure-16 3081728 384.4 ns/op 376 B/op 13 allocs/op
BenchmarkFieldMapDiveFailureParallel-16 6058137 204.0 ns/op 377 B/op 13 allocs/op
BenchmarkFieldMapDiveWithKeysSuccess-16 2544975 464.8 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysSuccessParallel-16 6661954 181.4 ns/op 288 B/op 14 allocs/op
BenchmarkFieldMapDiveWithKeysFailure-16 2435484 490.7 ns/op 553 B/op 16 allocs/op
BenchmarkFieldMapDiveWithKeysFailureParallel-16 4249617 282.0 ns/op 554 B/op 16 allocs/op
BenchmarkFieldCustomTypeSuccess-16 14943525 77.35 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeSuccessParallel-16 64051954 20.61 ns/op 32 B/op 2 allocs/op
BenchmarkFieldCustomTypeFailure-16 10721384 107.1 ns/op 184 B/op 3 allocs/op
BenchmarkFieldCustomTypeFailureParallel-16 18714495 69.77 ns/op 184 B/op 3 allocs/op
BenchmarkFieldOrTagSuccess-16 4063124 294.3 ns/op 16 B/op 1 allocs/op
BenchmarkFieldOrTagSuccessParallel-16 31903756 41.22 ns/op 18 B/op 1 allocs/op
BenchmarkFieldOrTagFailure-16 7748558 146.8 ns/op 216 B/op 5 allocs/op
BenchmarkFieldOrTagFailureParallel-16 13139854 92.05 ns/op 216 B/op 5 allocs/op
BenchmarkStructLevelValidationSuccess-16 16808389 70.25 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationSuccessParallel-16 90686955 14.47 ns/op 16 B/op 1 allocs/op
BenchmarkStructLevelValidationFailure-16 5818791 200.2 ns/op 264 B/op 7 allocs/op
BenchmarkStructLevelValidationFailureParallel-16 11115874 107.5 ns/op 264 B/op 7 allocs/op
BenchmarkStructSimpleCustomTypeSuccess-16 7764956 151.9 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeSuccessParallel-16 52316265 30.37 ns/op 32 B/op 2 allocs/op
BenchmarkStructSimpleCustomTypeFailure-16 4195429 277.2 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleCustomTypeFailureParallel-16 7305661 164.6 ns/op 432 B/op 10 allocs/op
BenchmarkStructFilteredSuccess-16 6312625 186.1 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredSuccessParallel-16 13684459 93.42 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailure-16 6751482 171.2 ns/op 216 B/op 5 allocs/op
BenchmarkStructFilteredFailureParallel-16 14146070 86.93 ns/op 216 B/op 5 allocs/op
BenchmarkStructPartialSuccess-16 6544448 177.3 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialSuccessParallel-16 13951946 88.73 ns/op 224 B/op 4 allocs/op
BenchmarkStructPartialFailure-16 4075833 287.5 ns/op 440 B/op 9 allocs/op
BenchmarkStructPartialFailureParallel-16 7490805 161.3 ns/op 440 B/op 9 allocs/op
BenchmarkStructExceptSuccess-16 4107187 281.4 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptSuccessParallel-16 15979173 80.86 ns/op 208 B/op 3 allocs/op
BenchmarkStructExceptFailure-16 4434372 264.3 ns/op 424 B/op 8 allocs/op
BenchmarkStructExceptFailureParallel-16 8081367 154.1 ns/op 424 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldSuccess-16 6459542 183.4 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldSuccessParallel-16 41013781 37.95 ns/op 56 B/op 3 allocs/op
BenchmarkStructSimpleCrossFieldFailure-16 4034998 292.1 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossFieldFailureParallel-16 11348446 115.3 ns/op 272 B/op 8 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccess-16 4448528 267.7 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel-16 26813619 48.33 ns/op 64 B/op 4 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailure-16 3090646 384.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleCrossStructCrossFieldFailureParallel-16 9870906 129.5 ns/op 288 B/op 9 allocs/op
BenchmarkStructSimpleSuccess-16 10675562 109.5 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleSuccessParallel-16 131159784 8.932 ns/op 0 B/op 0 allocs/op
BenchmarkStructSimpleFailure-16 4094979 286.6 ns/op 416 B/op 9 allocs/op
BenchmarkStructSimpleFailureParallel-16 7606663 157.9 ns/op 416 B/op 9 allocs/op
BenchmarkStructComplexSuccess-16 2073470 576.0 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexSuccessParallel-16 7821831 161.3 ns/op 224 B/op 5 allocs/op
BenchmarkStructComplexFailure-16 576358 2001 ns/op 3042 B/op 48 allocs/op
BenchmarkStructComplexFailureParallel-16 1000000 1171 ns/op 3041 B/op 48 allocs/op
BenchmarkOneof-16 22503973 52.82 ns/op 0 B/op 0 allocs/op
BenchmarkOneofParallel-16 8538474 140.4 ns/op 0 B/op 0 allocs/op
```
Complementary Software
----------------------
Here is a list of software that complements using this library either pre or post validation.
* [form](https://github.com/go-playground/form) - Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.
* [mold](https://github.com/go-playground/mold) - A general library to help modify or set data within data structures and other objects
How to Contribute
------
Make a pull request...
Maintenance and support for SDK major versions
----------------------------------------------
See prior discussion [here](https://github.com/go-playground/validator/discussions/1342) for more details.
This package is aligned with the [Go release policy](https://go.dev/doc/devel/release) in that support is guaranteed for
the two most recent major versions.
This does not mean the package will not work with older versions of Go, only that we reserve the right to increase the
MSGV(Minimum Supported Go Version) when the need arises to address Security issues/patches, OS issues & support or newly
introduced functionality that would greatly benefit the maintenance and/or usage of this package.
If and when the MSGV is increased it will be done so in a minimum of a `Minor` release bump.
License
-------
Distributed under MIT License, please see license file within the code for more details.
Maintainers
-----------
This project has grown large enough that more than one person is required to properly support the community.
If you are interested in becoming a maintainer please reach out to me https://github.com/deankarn
================================================
FILE: _examples/custom/main.go
================================================
package main
import (
"database/sql"
"database/sql/driver"
"fmt"
"reflect"
"github.com/go-playground/validator/v10"
)
// DbBackedUser User struct
type DbBackedUser struct {
Name sql.NullString `validate:"required"`
Age sql.NullInt64 `validate:"required"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
// register all sql.Null* types to use the ValidateValuer CustomTypeFunc
validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})
// build object for validation
x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}
err := validate.Struct(x)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
}
}
// ValidateValuer implements validator.CustomTypeFunc
func ValidateValuer(field reflect.Value) interface{} {
if valuer, ok := field.Interface().(driver.Valuer); ok {
val, err := valuer.Value()
if err == nil {
return val
}
// handle the error how you want
}
return nil
}
================================================
FILE: _examples/custom-validation/main.go
================================================
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// MyStruct ..
type MyStruct struct {
String string `validate:"is-awesome"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
validate.RegisterValidation("is-awesome", ValidateMyVal)
s := MyStruct{String: "awesome"}
err := validate.Struct(s)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
}
s.String = "not awesome"
err = validate.Struct(s)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
}
}
// ValidateMyVal implements validator.Func
func ValidateMyVal(fl validator.FieldLevel) bool {
return fl.Field().String() == "awesome"
}
================================================
FILE: _examples/dive/main.go
================================================
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
// Test ...
type Test struct {
Array []string `validate:"required,gt=0,dive,required"`
Map map[string]string `validate:"required,gt=0,dive,keys,keymax,endkeys,required,max=1000"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
// registering alias so we can see the differences between
// map key, value validation errors
validate.RegisterAlias("keymax", "max=10")
var test Test
val(test)
test.Array = []string{""}
test.Map = map[string]string{"test > than 10": ""}
val(test)
}
func val(test Test) {
fmt.Println("testing")
err := validate.Struct(test)
fmt.Println(err)
}
================================================
FILE: _examples/gin-upgrading-overriding/main.go
================================================
package main
import "github.com/gin-gonic/gin/binding"
func main() {
binding.Validator = new(defaultValidator)
// regular gin logic
}
================================================
FILE: _examples/gin-upgrading-overriding/v8_to_v9.go
================================================
package main
import (
"reflect"
"sync"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
type defaultValidator struct {
once sync.Once
validate *validator.Validate
}
var _ binding.StructValidator = &defaultValidator{}
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
if kindOfData(obj) == reflect.Struct {
v.lazyinit()
if err := v.validate.Struct(obj); err != nil {
return err
}
}
return nil
}
func (v *defaultValidator) Engine() interface{} {
v.lazyinit()
return v.validate
}
func (v *defaultValidator) lazyinit() {
v.once.Do(func() {
v.validate = validator.New()
v.validate.SetTagName("binding")
// add any custom validations etc. here
})
}
func kindOfData(data interface{}) reflect.Kind {
value := reflect.ValueOf(data)
valueType := value.Kind()
if valueType == reflect.Ptr {
valueType = value.Elem().Kind()
}
return valueType
}
================================================
FILE: _examples/http-transalations/main.go
================================================
package main
import (
"encoding/json"
"errors"
"net/http"
"strings"
"github.com/go-playground/locales/en"
"github.com/go-playground/locales/zh"
"github.com/go-playground/locales/zh_Hant_TW"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
zh_translations "github.com/go-playground/validator/v10/translations/zh"
zh_tw_translations "github.com/go-playground/validator/v10/translations/zh_tw"
)
var uni *ut.UniversalTranslator
// This example showcases how to use the Validator and UniversalTranslator with both Simplified and Traditional Chinese languages.
// To run the example:
// Step 1: go run _examples/http-transalations/main.go
// Step 2 - Simplified Chinese: curl -d '{"first_name":"foo"}' -H "Accept-Language: zh" -H "Content-Type: application/json" -X POST http://localhost:8081/users
// Step 3 - Traditional Chinese: curl -d '{"first_name":"foo"}' -H "Accept-Language: zh-Hant-TW" -H "Content-Type: application/json" -X POST http://localhost:8081/users
func main() {
validate := validator.New()
en := en.New()
uni = ut.New(en, en, zh.New(), zh_Hant_TW.New())
validate = validator.New()
enTrans, _ := uni.GetTranslator("en")
en_translations.RegisterDefaultTranslations(validate, enTrans)
zhTrans, _ := uni.GetTranslator("zh")
zh_translations.RegisterDefaultTranslations(validate, zhTrans)
zhHantTrans, _ := uni.GetTranslator("zh_Hant_TW")
zh_tw_translations.RegisterDefaultTranslations(validate, zhHantTrans)
type User struct {
FirstName string `json:"first_name" validate:"required"`
LastName string `json:"last_name" validate:"required"`
}
http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
// ... fill user value
var user User
// Header Accept-Language value is en or zh
trans, _ := uni.GetTranslator(strings.Replace(r.Header.Get("Accept-Language"), "-", "_", -1))
if err := validate.Struct(&user); err != nil {
var errs validator.ValidationErrors
var httpErrors []validator.ValidationErrorsTranslations
if errors.As(err, &errs) {
httpErrors = append(httpErrors, errs.Translate(trans))
}
r, _ := json.Marshal(httpErrors)
w.Write(r)
}
})
http.ListenAndServe(":8081", nil)
}
================================================
FILE: _examples/map-validation/main.go
================================================
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
var validate *validator.Validate
func main() {
validate = validator.New()
validateMap()
validateNestedMap()
}
func validateMap() {
user := map[string]interface{}{"name": "Arshiya Kiani", "email": "zytel3301@gmail.com"}
// Every rule will be applied to the item of the data that the offset of rule is pointing to.
// So if you have a field "email": "omitempty,required,email", the validator will apply these
// rules to offset of email in user data
rules := map[string]interface{}{"name": "required,min=8,max=32", "email": "omitempty,required,email"}
// ValidateMap will return map[string]error.
// The offset of every item in errs is the name of invalid field and the value
// is the message of error. If there was no error, ValidateMap method will
// return an EMPTY map of errors, not nil. If you want to check that
// if there was an error or not, you must check the length of the return value
errs := validate.ValidateMap(user, rules)
if len(errs) > 0 {
fmt.Println(errs)
// The user is invalid
}
// The user is valid
}
func validateNestedMap() {
data := map[string]interface{}{
"name": "Arshiya Kiani",
"email": "zytel3301@gmail.com",
"details": map[string]interface{}{
"family_members": map[string]interface{}{
"father_name": "Micheal",
"mother_name": "Hannah",
},
"salary": "1000",
"phones": []map[string]interface{}{
{
"number": "11-111-1111",
"remark": "home",
},
{
"number": "22-222-2222",
"remark": "work",
},
},
},
}
// Rules must be set as the structure as the data itself. If you want to dive into the
// map, just declare its rules as a map
rules := map[string]interface{}{
"name": "min=4,max=32",
"email": "required,email",
"details": map[string]interface{}{
"family_members": map[string]interface{}{
"father_name": "required,min=4,max=32",
"mother_name": "required,min=4,max=32",
},
"salary": "number",
"phones": map[string]interface{}{
"number": "required,min=4,max=32",
"remark": "required,min=1,max=32",
},
},
}
if len(validate.ValidateMap(data, rules)) == 0 {
// Data is valid
}
// Data is invalid
}
================================================
FILE: _examples/simple/main.go
================================================
package main
import (
"errors"
"fmt"
"github.com/go-playground/validator/v10"
)
// User contains user information
type User struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
Gender string `validate:"oneof=male female prefer_not_to"`
FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New(validator.WithRequiredStructEnabled())
validateStruct()
validateVariable()
}
func validateStruct() {
address := &Address{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
}
user := &User{
FirstName: "Badger",
LastName: "Smith",
Age: 135,
Gender: "male",
Email: "Badger.Smith@gmail.com",
FavouriteColor: "#000-",
Addresses: []*Address{address},
}
// returns nil or ValidationErrors ( []FieldError )
err := validate.Struct(user)
if err != nil {
// this check is only needed when your code could produce
// an invalid value for validation such as interface with nil
// value most including myself do not usually have code like this.
var invalidValidationError *validator.InvalidValidationError
if errors.As(err, &invalidValidationError) {
fmt.Println(err)
return
}
var validateErrs validator.ValidationErrors
if errors.As(err, &validateErrs) {
for _, e := range validateErrs {
fmt.Println(e.Namespace())
fmt.Println(e.Field())
fmt.Println(e.StructNamespace())
fmt.Println(e.StructField())
fmt.Println(e.Tag())
fmt.Println(e.ActualTag())
fmt.Println(e.Kind())
fmt.Println(e.Type())
fmt.Println(e.Value())
fmt.Println(e.Param())
fmt.Println()
}
}
// from here you can create your own error messages in whatever language you wish
return
}
// save user to database
}
func validateVariable() {
myEmail := "joeybloggs.gmail.com"
errs := validate.Var(myEmail, "required,email")
if errs != nil {
fmt.Println(errs) // output: Key: "" Error:Field validation for "" failed on the "email" tag
return
}
// email ok, move on
}
================================================
FILE: _examples/struct-level/main.go
================================================
package main
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strings"
"github.com/go-playground/validator/v10"
)
type validationError struct {
Namespace string `json:"namespace"` // can differ when a custom TagNameFunc is registered or
Field string `json:"field"` // by passing alt name to ReportError like below
StructNamespace string `json:"structNamespace"`
StructField string `json:"structField"`
Tag string `json:"tag"`
ActualTag string `json:"actualTag"`
Kind string `json:"kind"`
Type string `json:"type"`
Value string `json:"value"`
Param string `json:"param"`
Message string `json:"message"`
}
type Gender uint
const (
Male Gender = iota + 1
Female
Intersex
)
func (gender Gender) String() string {
terms := []string{"Male", "Female", "Intersex"}
if gender < Male || gender > Intersex {
return "unknown"
}
return terms[gender]
}
// User contains user information
type User struct {
FirstName string `json:"fname"`
LastName string `json:"lname"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `json:"e-mail" validate:"required,email"`
FavouriteColor string `validate:"hexcolor|rgb|rgba"`
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
Gender Gender `json:"gender" validate:"required,gender_custom_validation"`
}
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
// register function to get tag name from json tags.
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
if name == "-" {
return ""
}
return name
})
// register validation for 'User'
// NOTE: only have to register a non-pointer type for 'User', validator
// internally dereferences during it's type checks.
validate.RegisterStructValidation(UserStructLevelValidation, User{})
// register a custom validation for user genre on a line
// validates that an enum is within the interval
err := validate.RegisterValidation("gender_custom_validation", func(fl validator.FieldLevel) bool {
value := fl.Field().Interface().(Gender)
return value.String() != "unknown"
})
if err != nil {
fmt.Println(err)
return
}
// build 'User' info, normally posted data etc...
address := &Address{
Street: "Eavesdown Docks",
Planet: "Persphone",
Phone: "none",
City: "Unknown",
}
user := &User{
FirstName: "",
LastName: "",
Age: 45,
Email: "Badger.Smith@gmail",
FavouriteColor: "#000",
Addresses: []*Address{address},
}
// returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError )
err = validate.Struct(user)
if err != nil {
// this check is only needed when your code could produce
// an invalid value for validation such as interface with nil
// value most including myself do not usually have code like this.
var invalidValidationError *validator.InvalidValidationError
if errors.As(err, &invalidValidationError) {
fmt.Println(err)
return
}
var validateErrs validator.ValidationErrors
if errors.As(err, &validateErrs) {
for _, err := range validateErrs {
e := validationError{
Namespace: err.Namespace(),
Field: err.Field(),
StructNamespace: err.StructNamespace(),
StructField: err.StructField(),
Tag: err.Tag(),
ActualTag: err.ActualTag(),
Kind: fmt.Sprintf("%v", err.Kind()),
Type: fmt.Sprintf("%v", err.Type()),
Value: fmt.Sprintf("%v", err.Value()),
Param: err.Param(),
Message: err.Error(),
}
indent, err := json.MarshalIndent(e, "", " ")
if err != nil {
fmt.Println(err)
panic(err)
}
fmt.Println(string(indent))
}
}
// from here you can create your own error messages in whatever language you wish
return
}
// save user to database
}
// UserStructLevelValidation contains custom struct level validations that don't always
// make sense at the field validation level. For example, this function validates that either
// FirstName or LastName exist; could have done that with a custom field validation but then
// would have had to add it to both fields duplicating the logic + overhead, this way it's
// only validated once.
//
// NOTE: you may ask why wouldn't I just do this outside of validator, because doing this way
// hooks right into validator and you can combine with validation tags and still have a
// common error output format.
func UserStructLevelValidation(sl validator.StructLevel) {
user := sl.Current().Interface().(User)
if len(user.FirstName) == 0 && len(user.LastName) == 0 {
sl.ReportError(user.FirstName, "fname", "FirstName", "fnameorlname", "")
sl.ReportError(user.LastName, "lname", "LastName", "fnameorlname", "")
}
// plus can do more, even with different tag than "fnameorlname"
}
================================================
FILE: _examples/struct-map-rules-validation/main.go
================================================
package main
import (
"fmt"
"github.com/go-playground/validator/v10"
)
type Data struct {
Name string
Email string
Details *Details
}
type Details struct {
FamilyMembers *FamilyMembers
Salary string
}
type FamilyMembers struct {
FatherName string
MotherName string
}
type Data2 struct {
Name string
Age uint32
}
var validate = validator.New()
func main() {
validateStruct()
// output
// Key: 'Data2.Name' Error:Field validation for 'Name' failed on the 'min' tag
// Key: 'Data2.Age' Error:Field validation for 'Age' failed on the 'max' tag
validateStructNested()
// output
// Key: 'Data.Name' Error:Field validation for 'Name' failed on the 'max' tag
// Key: 'Data.Details.FamilyMembers' Error:Field validation for 'FamilyMembers' failed on the 'required' tag
}
func validateStruct() {
data := Data2{
Name: "leo",
Age: 1000,
}
rules := map[string]string{
"Name": "min=4,max=6",
"Age": "min=4,max=6",
}
validate.RegisterStructValidationMapRules(rules, Data2{})
err := validate.Struct(data)
fmt.Println(err)
fmt.Println()
}
func validateStructNested() {
data := Data{
Name: "11sdfddd111",
Email: "zytel3301@mail.com",
Details: &Details{
Salary: "1000",
},
}
rules1 := map[string]string{
"Name": "min=4,max=6",
"Email": "required,email",
"Details": "required",
}
rules2 := map[string]string{
"Salary": "number",
"FamilyMembers": "required",
}
rules3 := map[string]string{
"FatherName": "required,min=4,max=32",
"MotherName": "required,min=4,max=32",
}
validate.RegisterStructValidationMapRules(rules1, Data{})
validate.RegisterStructValidationMapRules(rules2, Details{})
validate.RegisterStructValidationMapRules(rules3, FamilyMembers{})
err := validate.Struct(data)
fmt.Println(err)
}
================================================
FILE: _examples/translations/main.go
================================================
package main
import (
"fmt"
"github.com/go-playground/locales/en"
ut "github.com/go-playground/universal-translator"
"github.com/go-playground/validator/v10"
en_translations "github.com/go-playground/validator/v10/translations/en"
)
// User contains user information
type User struct {
FirstName string `validate:"required"`
LastName string `validate:"required"`
Age uint8 `validate:"gte=0,lte=130"`
Email string `validate:"required,email"`
FavouriteColor string `validate:"iscolor"` // alias for 'hexcolor|rgb|rgba|hsl|hsla'
Addresses []*Address `validate:"required,dive,required"` // a person can have a home and cottage...
}
// Address houses a users address information
type Address struct {
Street string `validate:"required"`
City string `validate:"required"`
Planet string `validate:"required"`
Phone string `validate:"required"`
}
// use a single instance, it caches struct info
var (
uni *ut.UniversalTranslator
validate *validator.Validate
)
func main() {
// NOTE: omitting allot of error checking for brevity
en := en.New()
uni = ut.New(en, en)
// this is usually know or extracted from http 'Accept-Language' header
// also see uni.FindTranslator(...)
trans, _ := uni.GetTranslator("en")
validate = validator.New()
en_translations.RegisterDefaultTranslations(validate, trans)
translateAll(trans)
translateIndividual(trans)
translateOverride(trans) // yep you can specify your own in whatever locale you want!
}
func translateAll(trans ut.Translator) {
type User struct {
Username string `validate:"required"`
Tagline string `validate:"required,lt=10"`
Tagline2 string `validate:"required,gt=1"`
}
user := User{
Username: "Joeybloggs",
Tagline: "This tagline is way too long.",
Tagline2: "1",
}
err := validate.Struct(user)
if err != nil {
// translate all error at once
errs := err.(validator.ValidationErrors)
// returns a map with key = namespace & value = translated error
// NOTICE: 2 errors are returned and you'll see something surprising
// translations are i18n aware!!!!
// eg. '10 characters' vs '1 character'
fmt.Println(errs.Translate(trans))
}
}
func translateIndividual(trans ut.Translator) {
type User struct {
Username string `validate:"required"`
}
var user User
err := validate.Struct(user)
if err != nil {
errs := err.(validator.ValidationErrors)
for _, e := range errs {
// can translate each error one at a time.
fmt.Println(e.Translate(trans))
}
}
}
func translateOverride(trans ut.Translator) {
validate.RegisterTranslation("required", trans, func(ut ut.Translator) error {
return ut.Add("required", "{0} must have a value!", true) // see universal-translator for details
}, func(ut ut.Translator, fe validator.FieldError) string {
t, _ := ut.T("required", fe.Field())
return t
})
type User struct {
Username string `validate:"required"`
}
var user User
err := validate.Struct(user)
if err != nil {
errs := err.(validator.ValidationErrors)
for _, e := range errs {
// can translate each error one at a time.
fmt.Println(e.Translate(trans))
}
}
}
================================================
FILE: _examples/validate_fn/enum_enumer.go
================================================
// Code generated by "enumer -type=Enum"; DO NOT EDIT.
package main
import (
"fmt"
"strings"
)
const _EnumName = "ZeroOneTwoThree"
var _EnumIndex = [...]uint8{0, 4, 7, 10, 15}
const _EnumLowerName = "zeroonetwothree"
func (i Enum) String() string {
if i >= Enum(len(_EnumIndex)-1) {
return fmt.Sprintf("Enum(%d)", i)
}
return _EnumName[_EnumIndex[i]:_EnumIndex[i+1]]
}
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
func _EnumNoOp() {
var x [1]struct{}
_ = x[Zero-(0)]
_ = x[One-(1)]
_ = x[Two-(2)]
_ = x[Three-(3)]
}
var _EnumValues = []Enum{Zero, One, Two, Three}
var _EnumNameToValueMap = map[string]Enum{
_EnumName[0:4]: Zero,
_EnumLowerName[0:4]: Zero,
_EnumName[4:7]: One,
_EnumLowerName[4:7]: One,
_EnumName[7:10]: Two,
_EnumLowerName[7:10]: Two,
_EnumName[10:15]: Three,
_EnumLowerName[10:15]: Three,
}
var _EnumNames = []string{
_EnumName[0:4],
_EnumName[4:7],
_EnumName[7:10],
_EnumName[10:15],
}
// EnumString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func EnumString(s string) (Enum, error) {
if val, ok := _EnumNameToValueMap[s]; ok {
return val, nil
}
if val, ok := _EnumNameToValueMap[strings.ToLower(s)]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Enum values", s)
}
// EnumValues returns all values of the enum
func EnumValues() []Enum {
return _EnumValues
}
// EnumStrings returns a slice of all String values of the enum
func EnumStrings() []string {
strs := make([]string, len(_EnumNames))
copy(strs, _EnumNames)
return strs
}
// IsAEnum returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Enum) IsAEnum() bool {
for _, v := range _EnumValues {
if i == v {
return true
}
}
return false
}
================================================
FILE: _examples/validate_fn/go.mod
================================================
module github.com/peczenyj/validator/_examples/validate_fn
go 1.23.0
toolchain go1.24.4
replace github.com/go-playground/validator/v10 => ../../../validator
require github.com/go-playground/validator/v10 v10.26.0
require (
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
)
================================================
FILE: _examples/validate_fn/go.sum
================================================
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
================================================
FILE: _examples/validate_fn/main.go
================================================
package main
import (
"errors"
"fmt"
"github.com/go-playground/validator/v10"
)
//go:generate enumer -type=Enum
type Enum uint8
const (
Zero Enum = iota
One
Two
Three
)
func (e *Enum) Validate() error {
if e == nil {
return errors.New("can't be nil")
}
return nil
}
type Struct struct {
Foo *Enum `validate:"validateFn"` // uses Validate() error by default
Bar Enum `validate:"validateFn=IsAEnum"` // uses IsAEnum() bool provided by enumer
}
func main() {
validate := validator.New()
var x Struct
x.Bar = Enum(64)
if err := validate.Struct(x); err != nil {
fmt.Printf("Expected Err(s):\n%+v\n", err)
}
x = Struct{
Foo: new(Enum),
Bar: One,
}
if err := validate.Struct(x); err != nil {
fmt.Printf("Unexpected Err(s):\n%+v\n", err)
}
}
================================================
FILE: _examples/valuer/main.go
================================================
package main
import (
"errors"
"fmt"
"github.com/go-playground/validator/v10"
)
// Nullable wraps a generic value.
type Nullable[T any] struct {
Data T
}
// ValidatorValue returns the inner value that should be validated.
func (n Nullable[T]) ValidatorValue() any {
return n.Data
}
type Config struct {
Name string `validate:"required"`
}
type Record struct {
Config Nullable[Config] `validate:"required"`
}
// use a single instance of Validate, it caches struct info
var validate *validator.Validate
func main() {
validate = validator.New()
// valid case: ValidatorValue unwraps Config and Name passes required.
valid := Record{
Config: Nullable[Config]{
Data: Config{Name: "validator"},
},
}
err := validate.Struct(valid)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
}
// invalid case: Name is empty after unwrapping, so required fails on Config.Name.
invalid := Record{
Config: Nullable[Config]{},
}
err = validate.Struct(invalid)
if err != nil {
fmt.Printf("Err(s):\n%+v\n", err)
var validationErrs validator.ValidationErrors
if errors.As(err, &validationErrs) && len(validationErrs) > 0 {
fmt.Printf("First error namespace: %s\n", validationErrs[0].Namespace())
}
}
}
================================================
FILE: baked_in.go
================================================
package validator
import (
"bufio"
"bytes"
"cmp"
"context"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/fs"
"net"
"net/mail"
"net/url"
"os"
"reflect"
"runtime"
"strconv"
"strings"
"sync"
"syscall"
"time"
"unicode/utf8"
"golang.org/x/crypto/sha3"
"golang.org/x/text/language"
"github.com/gabriel-vasile/mimetype"
urn "github.com/leodido/go-urn"
)
// Func accepts a FieldLevel interface for all validation needs. The return
// value should be true when validation succeeds.
type Func func(fl FieldLevel) bool
// FuncCtx accepts a context.Context and FieldLevel interface for all
// validation needs. The return value should be true when validation succeeds.
type FuncCtx func(ctx context.Context, fl FieldLevel) bool
// wrapFunc wraps normal Func makes it compatible with FuncCtx
func wrapFunc(fn Func) FuncCtx {
if fn == nil {
return nil // be sure not to wrap a bad function.
}
return func(ctx context.Context, fl FieldLevel) bool {
return fn(fl)
}
}
var (
restrictedTags = map[string]struct{}{
diveTag: {},
keysTag: {},
endKeysTag: {},
structOnlyTag: {},
omitzero: {},
omitempty: {},
omitnil: {},
skipValidationTag: {},
utf8HexComma: {},
utf8Pipe: {},
noStructLevelTag: {},
requiredTag: {},
isdefault: {},
}
// bakedInAliases is a default mapping of a single validation tag that
// defines a common or complex set of validation(s) to simplify
// adding validation to structs.
bakedInAliases = map[string]string{
"iscolor": "hexcolor|rgb|rgba|hsl|hsla|cmyk",
"country_code": "iso3166_1_alpha2|iso3166_1_alpha3|iso3166_1_alpha_numeric",
"eu_country_code": "iso3166_1_alpha2_eu|iso3166_1_alpha3_eu|iso3166_1_alpha_numeric_eu",
}
// bakedInValidators is the default map of ValidationFunc
// you can add, remove or even replace items to suite your needs,
// or even disregard and use your own map if so desired.
bakedInValidators = map[string]Func{
"required": hasValue,
"required_if": requiredIf,
"required_unless": requiredUnless,
"skip_unless": skipUnless,
"required_with": requiredWith,
"required_with_all": requiredWithAll,
"required_without": requiredWithout,
"required_without_all": requiredWithoutAll,
"excluded_if": excludedIf,
"excluded_unless": excludedUnless,
"excluded_with": excludedWith,
"excluded_with_all": excludedWithAll,
"excluded_without": excludedWithout,
"excluded_without_all": excludedWithoutAll,
"isdefault": isDefault,
"len": hasLengthOf,
"min": hasMinOf,
"max": hasMaxOf,
"eq": isEq,
"eq_ignore_case": isEqIgnoreCase,
"ne": isNe,
"ne_ignore_case": isNeIgnoreCase,
"lt": isLt,
"lte": isLte,
"gt": isGt,
"gte": isGte,
"eqfield": isEqField,
"eqcsfield": isEqCrossStructField,
"necsfield": isNeCrossStructField,
"gtcsfield": isGtCrossStructField,
"gtecsfield": isGteCrossStructField,
"ltcsfield": isLtCrossStructField,
"ltecsfield": isLteCrossStructField,
"nefield": isNeField,
"gtefield": isGteField,
"gtfield": isGtField,
"ltefield": isLteField,
"ltfield": isLtField,
"fieldcontains": fieldContains,
"fieldexcludes": fieldExcludes,
"alpha": isAlpha,
"alphaspace": isAlphaSpace,
"alphanum": isAlphanum,
"alphanumspace": isAlphaNumericSpace,
"alphaunicode": isAlphaUnicode,
"alphanumunicode": isAlphanumUnicode,
"boolean": isBoolean,
"numeric": isNumeric,
"number": isNumber,
"hexadecimal": isHexadecimal,
"hexcolor": isHEXColor,
"rgb": isRGB,
"rgba": isRGBA,
"hsl": isHSL,
"hsla": isHSLA,
"cmyk": isCMYK,
"e164": isE164,
"email": isEmail,
"url": isURL,
"http_url": isHttpURL,
"https_url": isHttpsURL,
"uri": isURI,
"urn_rfc2141": isUrnRFC2141, // RFC 2141
"file": isFile,
"filepath": isFilePath,
"base32": isBase32,
"base64": isBase64,
"base64url": isBase64URL,
"base64rawurl": isBase64RawURL,
"contains": contains,
"containsany": containsAny,
"containsrune": containsRune,
"excludes": excludes,
"excludesall": excludesAll,
"excludesrune": excludesRune,
"startswith": startsWith,
"endswith": endsWith,
"startsnotwith": startsNotWith,
"endsnotwith": endsNotWith,
"image": isImage,
"isbn": isISBN,
"isbn10": isISBN10,
"isbn13": isISBN13,
"issn": isISSN,
"eth_addr": isEthereumAddress,
"eth_addr_checksum": isEthereumAddressChecksum,
"btc_addr": isBitcoinAddress,
"btc_addr_bech32": isBitcoinBech32Address,
"uuid": isUUID,
"uuid3": isUUID3,
"uuid4": isUUID4,
"uuid5": isUUID5,
"uuid_rfc4122": isUUIDRFC4122,
"uuid3_rfc4122": isUUID3RFC4122,
"uuid4_rfc4122": isUUID4RFC4122,
"uuid5_rfc4122": isUUID5RFC4122,
"ulid": isULID,
"md4": isMD4,
"md5": isMD5,
"sha256": isSHA256,
"sha384": isSHA384,
"sha512": isSHA512,
"ripemd128": isRIPEMD128,
"ripemd160": isRIPEMD160,
"tiger128": isTIGER128,
"tiger160": isTIGER160,
"tiger192": isTIGER192,
"ascii": isASCII,
"printascii": isPrintableASCII,
"multibyte": hasMultiByteCharacter,
"datauri": isDataURI,
"latitude": isLatitude,
"longitude": isLongitude,
"ssn": isSSN,
"ipv4": isIPv4,
"ipv6": isIPv6,
"ip": isIP,
"cidrv4": isCIDRv4,
"cidrv6": isCIDRv6,
"cidr": isCIDR,
"tcp4_addr": isTCP4AddrResolvable,
"tcp6_addr": isTCP6AddrResolvable,
"tcp_addr": isTCPAddrResolvable,
"udp4_addr": isUDP4AddrResolvable,
"udp6_addr": isUDP6AddrResolvable,
"udp_addr": isUDPAddrResolvable,
"ip4_addr": isIP4AddrResolvable,
"ip6_addr": isIP6AddrResolvable,
"ip_addr": isIPAddrResolvable,
"unix_addr": isUnixAddrResolvable,
"uds_exists": isUnixDomainSocketExists,
"mac": isMAC,
"hostname": isHostnameRFC952, // RFC 952
"hostname_rfc1123": isHostnameRFC1123, // RFC 1123
"fqdn": isFQDN,
"unique": isUnique,
"oneof": isOneOf,
"oneofci": isOneOfCI,
"html": isHTML,
"html_encoded": isHTMLEncoded,
"url_encoded": isURLEncoded,
"dir": isDir,
"dirpath": isDirPath,
"json": isJSON,
"jwt": isJWT,
"hostname_port": isHostnamePort,
"port": isPort,
"lowercase": isLowercase,
"uppercase": isUppercase,
"datetime": isDatetime,
"timezone": isTimeZone,
"iso3166_1_alpha2": isIso3166Alpha2,
"iso3166_1_alpha2_eu": isIso3166Alpha2EU,
"iso3166_1_alpha3": isIso3166Alpha3,
"iso3166_1_alpha3_eu": isIso3166Alpha3EU,
"iso3166_1_alpha_numeric": isIso3166AlphaNumeric,
"iso3166_1_alpha_numeric_eu": isIso3166AlphaNumericEU,
"iso3166_2": isIso31662,
"iso4217": isIso4217,
"iso4217_numeric": isIso4217Numeric,
"bcp47_language_tag": isBCP47LanguageTag,
"postcode_iso3166_alpha2": isPostcodeByIso3166Alpha2,
"postcode_iso3166_alpha2_field": isPostcodeByIso3166Alpha2Field,
"bic_iso_9362_2014": isIsoBic2014Format,
"bic": isIsoBic2022Format,
"semver": isSemverFormat,
"dns_rfc1035_label": isDnsRFC1035LabelFormat,
"credit_card": isCreditCard,
"cve": isCveFormat,
"luhn_checksum": hasLuhnChecksum,
"mongodb": isMongoDBObjectId,
"mongodb_connection_string": isMongoDBConnectionString,
"cron": isCron,
"spicedb": isSpiceDB,
"ein": isEIN,
"validateFn": isValidateFn,
}
)
var (
oneofValsCache = map[string][]string{}
oneofValsCacheRWLock = sync.RWMutex{}
)
func parseOneOfParam2(s string) []string {
oneofValsCacheRWLock.RLock()
vals, ok := oneofValsCache[s]
oneofValsCacheRWLock.RUnlock()
if !ok {
oneofValsCacheRWLock.Lock()
vals = splitParamsRegex().FindAllString(s, -1)
for i := 0; i < len(vals); i++ {
vals[i] = strings.ReplaceAll(vals[i], "'", "")
}
oneofValsCache[s] = vals
oneofValsCacheRWLock.Unlock()
}
return vals
}
func isURLEncoded(fl FieldLevel) bool {
return uRLEncodedRegex().MatchString(fl.Field().String())
}
func isHTMLEncoded(fl FieldLevel) bool {
return hTMLEncodedRegex().MatchString(fl.Field().String())
}
func isHTML(fl FieldLevel) bool {
return hTMLRegex().MatchString(fl.Field().String())
}
func isOneOf(fl FieldLevel) bool {
vals := parseOneOfParam2(fl.Param())
field := fl.Field()
var v string
switch field.Kind() {
case reflect.String:
v = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v = strconv.FormatUint(field.Uint(), 10)
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
for i := 0; i < len(vals); i++ {
if vals[i] == v {
return true
}
}
return false
}
// isOneOfCI is the validation function for validating if the current field's value is one of the provided string values (case insensitive).
func isOneOfCI(fl FieldLevel) bool {
vals := parseOneOfParam2(fl.Param())
field := fl.Field()
if field.Kind() != reflect.String {
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
v := field.String()
for _, val := range vals {
if strings.EqualFold(val, v) {
return true
}
}
return false
}
// isUnique is the validation function for validating if each array|slice|map value is unique
func isUnique(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
// sentinel used as map key for nil values
var nilKey = struct{}{}
switch field.Kind() {
case reflect.Slice, reflect.Array:
seen := make(map[interface{}]struct{})
for i := 0; i < field.Len(); i++ {
elem := field.Index(i)
// -------- unique (no param) --------
if param == "" {
var key interface{}
if elem.Kind() == reflect.Ptr {
if elem.IsNil() {
key = nilKey
} else {
key = elem.Elem().Interface() // <-- compare underlying value
}
} else {
key = elem.Interface()
}
if _, ok := seen[key]; ok {
return false
}
seen[key] = struct{}{}
continue
}
// -------- unique=Field --------
if elem.Kind() == reflect.Ptr {
if elem.IsNil() {
if _, ok := seen[nilKey]; ok {
return false
}
seen[nilKey] = struct{}{}
continue
}
elem = elem.Elem()
}
if elem.Kind() != reflect.Struct {
panic(fmt.Sprintf("Bad field type %s", elem.Type()))
}
sf := elem.FieldByName(param)
if !sf.IsValid() {
panic(fmt.Sprintf("Bad field name %s", param))
}
var key interface{}
if sf.Kind() == reflect.Ptr {
if sf.IsNil() {
key = nilKey
} else {
key = sf.Elem().Interface()
}
} else {
key = sf.Interface()
}
if _, ok := seen[key]; ok {
return false
}
seen[key] = struct{}{}
}
return true
case reflect.Map:
seen := make(map[interface{}]struct{})
for _, k := range field.MapKeys() {
val := field.MapIndex(k)
var key interface{}
if val.Kind() == reflect.Ptr {
if val.IsNil() {
key = nilKey
} else {
key = val.Elem().Interface() // <-- compare underlying value
}
} else {
key = val.Interface()
}
if _, ok := seen[key]; ok {
return false
}
seen[key] = struct{}{}
}
return true
default:
if parent := fl.Parent(); parent.Kind() == reflect.Struct {
uniqueField := parent.FieldByName(param)
if !uniqueField.IsValid() {
panic(fmt.Sprintf("Bad field name provided %s", param))
}
if uniqueField.Kind() != field.Kind() {
panic(fmt.Sprintf("Bad field type %s:%s", field.Type(), uniqueField.Type()))
}
return getValue(field) != getValue(uniqueField)
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
}
// isMAC is the validation function for validating if the field's value is a valid MAC address.
func isMAC(fl FieldLevel) bool {
_, err := net.ParseMAC(fl.Field().String())
return err == nil
}
// isCIDRv4 is the validation function for validating if the field's value is a valid v4 CIDR address.
func isCIDRv4(fl FieldLevel) bool {
ip, net, err := net.ParseCIDR(fl.Field().String())
return err == nil && ip.To4() != nil && net.IP.Equal(ip)
}
// isCIDRv6 is the validation function for validating if the field's value is a valid v6 CIDR address.
func isCIDRv6(fl FieldLevel) bool {
ip, _, err := net.ParseCIDR(fl.Field().String())
return err == nil && ip.To4() == nil
}
// isCIDR is the validation function for validating if the field's value is a valid v4 or v6 CIDR address.
func isCIDR(fl FieldLevel) bool {
_, _, err := net.ParseCIDR(fl.Field().String())
return err == nil
}
// isIPv4 is the validation function for validating if a value is a valid v4 IP address.
func isIPv4(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String())
return ip != nil && ip.To4() != nil
}
// isIPv6 is the validation function for validating if the field's value is a valid v6 IP address.
func isIPv6(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String())
return ip != nil && ip.To4() == nil
}
// isIP is the validation function for validating if the field's value is a valid v4 or v6 IP address.
func isIP(fl FieldLevel) bool {
ip := net.ParseIP(fl.Field().String())
return ip != nil
}
// isSSN is the validation function for validating if the field's value is a valid SSN.
func isSSN(fl FieldLevel) bool {
field := fl.Field()
if field.Len() != 11 {
return false
}
return sSNRegex().MatchString(field.String())
}
// isLongitude is the validation function for validating if the field's value is a valid longitude coordinate.
func isLongitude(fl FieldLevel) bool {
field := fl.Field()
var v string
switch field.Kind() {
case reflect.String:
v = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v = strconv.FormatUint(field.Uint(), 10)
case reflect.Float32:
v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
case reflect.Float64:
v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
return longitudeRegex().MatchString(v)
}
// isLatitude is the validation function for validating if the field's value is a valid latitude coordinate.
func isLatitude(fl FieldLevel) bool {
field := fl.Field()
var v string
switch field.Kind() {
case reflect.String:
v = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v = strconv.FormatUint(field.Uint(), 10)
case reflect.Float32:
v = strconv.FormatFloat(field.Float(), 'f', -1, 32)
case reflect.Float64:
v = strconv.FormatFloat(field.Float(), 'f', -1, 64)
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
return latitudeRegex().MatchString(v)
}
// isDataURI is the validation function for validating if the field's value is a valid data URI.
func isDataURI(fl FieldLevel) bool {
uri := strings.SplitN(fl.Field().String(), ",", 2)
if len(uri) != 2 {
return false
}
if !dataURIRegex().MatchString(uri[0]) {
return false
}
return base64Regex().MatchString(uri[1])
}
// hasMultiByteCharacter is the validation function for validating if the field's value has a multi byte character.
func hasMultiByteCharacter(fl FieldLevel) bool {
field := fl.Field()
if field.Len() == 0 {
return true
}
return multibyteRegex().MatchString(field.String())
}
// isPrintableASCII is the validation function for validating if the field's value is a valid printable ASCII character.
func isPrintableASCII(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
return printableASCIIRegex().MatchString(field.String())
}
return false
}
// isASCII is the validation function for validating if the field's value is a valid ASCII character.
func isASCII(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
return aSCIIRegex().MatchString(field.String())
}
return false
}
// isUUID5 is the validation function for validating if the field's value is a valid v5 UUID.
func isUUID5(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID5Regex, fl)
}
// isUUID4 is the validation function for validating if the field's value is a valid v4 UUID.
func isUUID4(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID4Regex, fl)
}
// isUUID3 is the validation function for validating if the field's value is a valid v3 UUID.
func isUUID3(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID3Regex, fl)
}
// isUUID is the validation function for validating if the field's value is a valid UUID of any version.
func isUUID(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUIDRegex, fl)
}
// isUUID5RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v5 UUID.
func isUUID5RFC4122(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID5RFC4122Regex, fl)
}
// isUUID4RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v4 UUID.
func isUUID4RFC4122(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID4RFC4122Regex, fl)
}
// isUUID3RFC4122 is the validation function for validating if the field's value is a valid RFC4122 v3 UUID.
func isUUID3RFC4122(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUID3RFC4122Regex, fl)
}
// isUUIDRFC4122 is the validation function for validating if the field's value is a valid RFC4122 UUID of any version.
func isUUIDRFC4122(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uUIDRFC4122Regex, fl)
}
// isULID is the validation function for validating if the field's value is a valid ULID.
func isULID(fl FieldLevel) bool {
return fieldMatchesRegexByStringerValOrString(uLIDRegex, fl)
}
// isMD4 is the validation function for validating if the field's value is a valid MD4.
func isMD4(fl FieldLevel) bool {
return md4Regex().MatchString(fl.Field().String())
}
// isMD5 is the validation function for validating if the field's value is a valid MD5.
func isMD5(fl FieldLevel) bool {
return md5Regex().MatchString(fl.Field().String())
}
// isSHA256 is the validation function for validating if the field's value is a valid SHA256.
func isSHA256(fl FieldLevel) bool {
return sha256Regex().MatchString(fl.Field().String())
}
// isSHA384 is the validation function for validating if the field's value is a valid SHA384.
func isSHA384(fl FieldLevel) bool {
return sha384Regex().MatchString(fl.Field().String())
}
// isSHA512 is the validation function for validating if the field's value is a valid SHA512.
func isSHA512(fl FieldLevel) bool {
return sha512Regex().MatchString(fl.Field().String())
}
// isRIPEMD128 is the validation function for validating if the field's value is a valid PIPEMD128.
func isRIPEMD128(fl FieldLevel) bool {
return ripemd128Regex().MatchString(fl.Field().String())
}
// isRIPEMD160 is the validation function for validating if the field's value is a valid PIPEMD160.
func isRIPEMD160(fl FieldLevel) bool {
return ripemd160Regex().MatchString(fl.Field().String())
}
// isTIGER128 is the validation function for validating if the field's value is a valid TIGER128.
func isTIGER128(fl FieldLevel) bool {
return tiger128Regex().MatchString(fl.Field().String())
}
// isTIGER160 is the validation function for validating if the field's value is a valid TIGER160.
func isTIGER160(fl FieldLevel) bool {
return tiger160Regex().MatchString(fl.Field().String())
}
// isTIGER192 is the validation function for validating if the field's value is a valid isTIGER192.
func isTIGER192(fl FieldLevel) bool {
return tiger192Regex().MatchString(fl.Field().String())
}
// isISBN is the validation function for validating if the field's value is a valid v10 or v13 ISBN.
func isISBN(fl FieldLevel) bool {
return isISBN10(fl) || isISBN13(fl)
}
// isISBN13 is the validation function for validating if the field's value is a valid v13 ISBN.
func isISBN13(fl FieldLevel) bool {
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 4), " ", "", 4)
if !iSBN13Regex().MatchString(s) {
return false
}
var checksum int32
var i int32
factor := []int32{1, 3}
for i = 0; i < 12; i++ {
checksum += factor[i%2] * int32(s[i]-'0')
}
return (int32(s[12]-'0'))-((10-(checksum%10))%10) == 0
}
// isISBN10 is the validation function for validating if the field's value is a valid v10 ISBN.
func isISBN10(fl FieldLevel) bool {
s := strings.Replace(strings.Replace(fl.Field().String(), "-", "", 3), " ", "", 3)
if !iSBN10Regex().MatchString(s) {
return false
}
var checksum int32
var i int32
for i = 0; i < 9; i++ {
checksum += (i + 1) * int32(s[i]-'0')
}
if s[9] == 'X' {
checksum += 10 * 10
} else {
checksum += 10 * int32(s[9]-'0')
}
return checksum%11 == 0
}
// isISSN is the validation function for validating if the field's value is a valid ISSN.
func isISSN(fl FieldLevel) bool {
s := fl.Field().String()
if !iSSNRegex().MatchString(s) {
return false
}
s = strings.ReplaceAll(s, "-", "")
pos := 8
checksum := 0
for i := 0; i < 7; i++ {
checksum += pos * int(s[i]-'0')
pos--
}
if s[7] == 'X' {
checksum += 10
} else {
checksum += int(s[7] - '0')
}
return checksum%11 == 0
}
// isEthereumAddress is the validation function for validating if the field's value is a valid Ethereum address.
func isEthereumAddress(fl FieldLevel) bool {
address := fl.Field().String()
return ethAddressRegex().MatchString(address)
}
// isEthereumAddressChecksum is the validation function for validating if the field's value is a valid checksummed Ethereum address.
func isEthereumAddressChecksum(fl FieldLevel) bool {
address := fl.Field().String()
if !ethAddressRegex().MatchString(address) {
return false
}
// Checksum validation. Reference: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md
address = address[2:] // Skip "0x" prefix.
h := sha3.NewLegacyKeccak256()
// hash.Hash's io.Writer implementation says it never returns an error. https://golang.org/pkg/hash/#Hash
_, _ = h.Write([]byte(strings.ToLower(address)))
hash := hex.EncodeToString(h.Sum(nil))
for i := 0; i < len(address); i++ {
if address[i] <= '9' { // Skip 0-9 digits: they don't have upper/lower-case.
continue
}
if hash[i] > '7' && address[i] >= 'a' || hash[i] <= '7' && address[i] <= 'F' {
return false
}
}
return true
}
// isBitcoinAddress is the validation function for validating if the field's value is a valid btc address
func isBitcoinAddress(fl FieldLevel) bool {
address := fl.Field().String()
if !btcAddressRegex().MatchString(address) {
return false
}
alphabet := []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
decode := [25]byte{}
for _, n := range []byte(address) {
d := bytes.IndexByte(alphabet, n)
for i := 24; i >= 0; i-- {
d += 58 * int(decode[i])
decode[i] = byte(d % 256)
d /= 256
}
}
h := sha256.New()
_, _ = h.Write(decode[:21])
d := h.Sum([]byte{})
h = sha256.New()
_, _ = h.Write(d)
validchecksum := [4]byte{}
computedchecksum := [4]byte{}
copy(computedchecksum[:], h.Sum(d[:0]))
copy(validchecksum[:], decode[21:])
return validchecksum == computedchecksum
}
// isBitcoinBech32Address is the validation function for validating if the field's value is a valid bech32 btc address
func isBitcoinBech32Address(fl FieldLevel) bool {
address := fl.Field().String()
if !btcLowerAddressRegexBech32().MatchString(address) && !btcUpperAddressRegexBech32().MatchString(address) {
return false
}
am := len(address) % 8
if am == 0 || am == 3 || am == 5 {
return false
}
address = strings.ToLower(address)
alphabet := "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
hr := []int{3, 3, 0, 2, 3} // the human readable part will always be bc
addr := address[3:]
dp := make([]int, 0, len(addr))
for _, c := range addr {
dp = append(dp, strings.IndexRune(alphabet, c))
}
ver := dp[0]
if ver < 0 || ver > 16 {
return false
}
if ver == 0 {
if len(address) != 42 && len(address) != 62 {
return false
}
}
values := append(hr, dp...)
GEN := []int{0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3}
p := 1
for _, v := range values {
b := p >> 25
p = (p&0x1ffffff)<<5 ^ v
for i := 0; i < 5; i++ {
if (b>>uint(i))&1 == 1 {
p ^= GEN[i]
}
}
}
if p != 1 {
return false
}
b := uint(0)
acc := 0
mv := (1 << 5) - 1
var sw []int
for _, v := range dp[1 : len(dp)-6] {
acc = (acc << 5) | v
b += 5
for b >= 8 {
b -= 8
sw = append(sw, (acc>>b)&mv)
}
}
if len(sw) < 2 || len(sw) > 40 {
return false
}
return true
}
// excludesRune is the validation function for validating that the field's value does not contain the rune specified within the param.
func excludesRune(fl FieldLevel) bool {
return !containsRune(fl)
}
// excludesAll is the validation function for validating that the field's value does not contain any of the characters specified within the param.
func excludesAll(fl FieldLevel) bool {
return !containsAny(fl)
}
// excludes is the validation function for validating that the field's value does not contain the text specified within the param.
func excludes(fl FieldLevel) bool {
return !contains(fl)
}
// containsRune is the validation function for validating that the field's value contains the rune specified within the param.
func containsRune(fl FieldLevel) bool {
r, _ := utf8.DecodeRuneInString(fl.Param())
return strings.ContainsRune(fl.Field().String(), r)
}
// containsAny is the validation function for validating that the field's value contains any of the characters specified within the param.
func containsAny(fl FieldLevel) bool {
return strings.ContainsAny(fl.Field().String(), fl.Param())
}
// contains is the validation function for validating that the field's value contains the text specified within the param.
func contains(fl FieldLevel) bool {
return strings.Contains(fl.Field().String(), fl.Param())
}
// startsWith is the validation function for validating that the field's value starts with the text specified within the param.
func startsWith(fl FieldLevel) bool {
return strings.HasPrefix(fl.Field().String(), fl.Param())
}
// endsWith is the validation function for validating that the field's value ends with the text specified within the param.
func endsWith(fl FieldLevel) bool {
return strings.HasSuffix(fl.Field().String(), fl.Param())
}
// startsNotWith is the validation function for validating that the field's value does not start with the text specified within the param.
func startsNotWith(fl FieldLevel) bool {
return !startsWith(fl)
}
// endsNotWith is the validation function for validating that the field's value does not end with the text specified within the param.
func endsNotWith(fl FieldLevel) bool {
return !endsWith(fl)
}
// fieldContains is the validation function for validating if the current field's value contains the field specified by the param's value.
func fieldContains(fl FieldLevel) bool {
field := fl.Field()
currentField, _, ok := fl.GetStructFieldOK()
if !ok {
return false
}
return strings.Contains(field.String(), currentField.String())
}
// fieldExcludes is the validation function for validating if the current field's value excludes the field specified by the param's value.
func fieldExcludes(fl FieldLevel) bool {
field := fl.Field()
currentField, _, ok := fl.GetStructFieldOK()
if !ok {
return true
}
return !strings.Contains(field.String(), currentField.String())
}
// isNeField is the validation function for validating if the current field's value is not equal to the field specified by the param's value.
func isNeField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return true
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() != currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() != currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() != currentField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) != int64(currentField.Len())
case reflect.Bool:
return field.Bool() != currentField.Bool()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
t := getValue(currentField).(time.Time)
fieldTime := getValue(field).(time.Time)
return !fieldTime.Equal(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return true
}
}
// default reflect.String:
return field.String() != currentField.String()
}
// isNe is the validation function for validating that the field's value does not equal the provided param value.
func isNe(fl FieldLevel) bool {
return !isEq(fl)
}
// isNeIgnoreCase is the validation function for validating that the field's string value does not equal the
// provided param value. The comparison is case-insensitive
func isNeIgnoreCase(fl FieldLevel) bool {
return !isEqIgnoreCase(fl)
}
// isLteCrossStructField is the validation function for validating if the current field's value is less than or equal to the field, within a separate struct, specified by the param's value.
func isLteCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() <= topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() <= topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() <= topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) <= int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
fieldTime := getValue(field.Convert(timeType)).(time.Time)
topTime := getValue(topField.Convert(timeType)).(time.Time)
return fieldTime.Before(topTime) || fieldTime.Equal(topTime)
}
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
}
// default reflect.String:
return field.String() <= topField.String()
}
// isLtCrossStructField is the validation function for validating if the current field's value is less than the field, within a separate struct, specified by the param's value.
// NOTE: This is exposed for use within your own custom functions and not intended to be called directly.
func isLtCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() < topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() < topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() < topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) < int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
fieldTime := getValue(field.Convert(timeType)).(time.Time)
topTime := getValue(topField.Convert(timeType)).(time.Time)
return fieldTime.Before(topTime)
}
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
}
// default reflect.String:
return field.String() < topField.String()
}
// isGteCrossStructField is the validation function for validating if the current field's value is greater than or equal to the field, within a separate struct, specified by the param's value.
func isGteCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() >= topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() >= topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() >= topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) >= int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
fieldTime := getValue(field.Convert(timeType)).(time.Time)
topTime := getValue(topField.Convert(timeType)).(time.Time)
return fieldTime.After(topTime) || fieldTime.Equal(topTime)
}
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
}
// default reflect.String:
return field.String() >= topField.String()
}
// isGtCrossStructField is the validation function for validating if the current field's value is greater than the field, within a separate struct, specified by the param's value.
func isGtCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() > topField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() > topField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() > topField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) > int64(topField.Len())
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
fieldTime := getValue(field.Convert(timeType)).(time.Time)
topTime := getValue(topField.Convert(timeType)).(time.Time)
return fieldTime.After(topTime)
}
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
}
// default reflect.String:
return field.String() > topField.String()
}
// isNeCrossStructField is the validation function for validating that the current field's value is not equal to the field, within a separate struct, specified by the param's value.
func isNeCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return true
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return topField.Int() != field.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return topField.Uint() != field.Uint()
case reflect.Float32, reflect.Float64:
return topField.Float() != field.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(topField.Len()) != int64(field.Len())
case reflect.Bool:
return topField.Bool() != field.Bool()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
t := getValue(field.Convert(timeType)).(time.Time)
fieldTime := getValue(topField.Convert(timeType)).(time.Time)
return !fieldTime.Equal(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return true
}
}
// default reflect.String:
return topField.String() != field.String()
}
// isEqCrossStructField is the validation function for validating that the current field's value is equal to the field, within a separate struct, specified by the param's value.
func isEqCrossStructField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
topField, topKind, ok := fl.GetStructFieldOK()
if !ok || topKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return topField.Int() == field.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return topField.Uint() == field.Uint()
case reflect.Float32, reflect.Float64:
return topField.Float() == field.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(topField.Len()) == int64(field.Len())
case reflect.Bool:
return topField.Bool() == field.Bool()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && topField.Type().ConvertibleTo(timeType) {
t := getValue(field.Convert(timeType)).(time.Time)
fieldTime := getValue(topField.Convert(timeType)).(time.Time)
return fieldTime.Equal(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != topField.Type() {
return false
}
}
// default reflect.String:
return topField.String() == field.String()
}
// isEqField is the validation function for validating if the current field's value is equal to the field specified by the param's value.
func isEqField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() == currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() == currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() == currentField.Float()
case reflect.Slice, reflect.Map, reflect.Array:
return int64(field.Len()) == int64(currentField.Len())
case reflect.Bool:
return field.Bool() == currentField.Bool()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
t := getValue(currentField.Convert(timeType)).(time.Time)
fieldTime := getValue(field.Convert(timeType)).(time.Time)
return fieldTime.Equal(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
}
// default reflect.String:
return field.String() == currentField.String()
}
// isEq is the validation function for validating if the current field's value is equal to the param's value.
func isEq(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
return field.String() == param
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) == p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asIntFromType(field.Type(), param)
return field.Int() == p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() == p
case reflect.Float32:
p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
return field.Float() == p
case reflect.Bool:
p := asBool(param)
return field.Bool() == p
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isEqIgnoreCase is the validation function for validating if the current field's string value is
// equal to the param's value.
// The comparison is case-insensitive.
func isEqIgnoreCase(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
return strings.EqualFold(field.String(), param)
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isPostcodeByIso3166Alpha2 validates by value which is country code in iso 3166 alpha 2
// example: `postcode_iso3166_alpha2=US`
func isPostcodeByIso3166Alpha2(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
postcodeRegexInit.Do(initPostcodes)
reg, found := postCodeRegexDict[param]
if !found {
return false
}
return reg.MatchString(field.String())
}
// isPostcodeByIso3166Alpha2Field validates by field which represents for a value of country code in iso 3166 alpha 2
// example: `postcode_iso3166_alpha2_field=CountryCode`
func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
field := fl.Field()
params := parseOneOfParam2(fl.Param())
if len(params) != 1 {
return false
}
currentField, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), params[0])
if !found {
return false
}
if kind != reflect.String {
panic(fmt.Sprintf("Bad field type %s", currentField.Type()))
}
postcodeRegexInit.Do(initPostcodes)
reg, found := postCodeRegexDict[currentField.String()]
if !found {
return false
}
return reg.MatchString(field.String())
}
// isBase32 is the validation function for validating if the current field's value is a valid base 32.
func isBase32(fl FieldLevel) bool {
return base32Regex().MatchString(fl.Field().String())
}
// isBase64 is the validation function for validating if the current field's value is a valid base 64.
func isBase64(fl FieldLevel) bool {
return base64Regex().MatchString(fl.Field().String())
}
// isBase64URL is the validation function for validating if the current field's value is a valid base64 URL safe string.
func isBase64URL(fl FieldLevel) bool {
return base64URLRegex().MatchString(fl.Field().String())
}
// isBase64RawURL is the validation function for validating if the current field's value is a valid base64 URL safe string without '=' padding.
func isBase64RawURL(fl FieldLevel) bool {
return base64RawURLRegex().MatchString(fl.Field().String())
}
// isURI is the validation function for validating if the current field's value is a valid URI.
func isURI(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
s := field.String()
// checks needed as of Go 1.6 because of change https://github.com/golang/go/commit/617c93ce740c3c3cc28cdd1a0d712be183d0b328#diff-6c2d018290e298803c0c9419d8739885L195
// emulate browser and strip the '#' suffix prior to validation. see issue-#237
if i := strings.Index(s, "#"); i > -1 {
s = s[:i]
}
if len(s) == 0 {
return false
}
_, err := url.ParseRequestURI(s)
return err == nil
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isURL is the validation function for validating if the current field's value is a valid URL.
func isURL(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
s := strings.ToLower(field.String())
if len(s) == 0 {
return false
}
url, err := url.Parse(s)
if err != nil || url.Scheme == "" {
return false
}
isFileScheme := url.Scheme == "file"
if (isFileScheme && (len(url.Path) == 0 || url.Path == "/")) || (!isFileScheme && len(url.Host) == 0 && len(url.Fragment) == 0 && len(url.Opaque) == 0) {
return false
}
return true
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isHttpURL is the validation function for validating if the current field's value is a valid HTTP(s) URL.
func isHttpURL(fl FieldLevel) bool {
if !isURL(fl) {
return false
}
field := fl.Field()
switch field.Kind() {
case reflect.String:
s := strings.ToLower(field.String())
url, err := url.Parse(s)
if err != nil || url.Host == "" {
return false
}
return url.Scheme == "http" || url.Scheme == "https"
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isHttpsURL is the validation function for validating if the current field's value is a valid HTTPS-only URL.
func isHttpsURL(fl FieldLevel) bool {
if !isURL(fl) {
return false
}
field := fl.Field()
switch field.Kind() {
case reflect.String:
s := strings.ToLower(field.String())
url, err := url.Parse(s)
if err != nil || url.Host == "" {
return false
}
return url.Scheme == "https"
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isUrnRFC2141 is the validation function for validating if the current field's value is a valid URN as per RFC 2141.
func isUrnRFC2141(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
str := field.String()
_, match := urn.Parse([]byte(str))
return match
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isFile is the validation function for validating if the current field's value is a valid existing file path.
func isFile(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
fileInfo, err := os.Stat(field.String())
if err != nil {
return false
}
return !fileInfo.IsDir()
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isImage is the validation function for validating if the current field's value contains the path to a valid image file
func isImage(fl FieldLevel) bool {
mimetypes := map[string]bool{
"image/bmp": true,
"image/cis-cod": true,
"image/gif": true,
"image/ief": true,
"image/jpeg": true,
"image/jp2": true,
"image/jpx": true,
"image/jpm": true,
"image/pipeg": true,
"image/png": true,
"image/svg+xml": true,
"image/tiff": true,
"image/webp": true,
"image/x-cmu-raster": true,
"image/x-cmx": true,
"image/x-icon": true,
"image/x-portable-anymap": true,
"image/x-portable-bitmap": true,
"image/x-portable-graymap": true,
"image/x-portable-pixmap": true,
"image/x-rgb": true,
"image/x-xbitmap": true,
"image/x-xpixmap": true,
"image/x-xwindowdump": true,
}
field := fl.Field()
switch field.Kind() {
case reflect.String:
filePath := field.String()
fileInfo, err := os.Stat(filePath)
if err != nil {
return false
}
if fileInfo.IsDir() {
return false
}
file, err := os.Open(filePath)
if err != nil {
return false
}
defer func() {
_ = file.Close()
}()
mime, err := mimetype.DetectReader(file)
if err != nil {
return false
}
if _, ok := mimetypes[mime.String()]; ok {
return true
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isFilePath is the validation function for validating if the current field's value is a valid file path.
func isFilePath(fl FieldLevel) bool {
var exists bool
var err error
field := fl.Field()
// Not valid if it is a directory.
if isDir(fl) {
return false
}
// If it exists, it obviously is valid.
// This is done first to avoid code duplication and unnecessary additional logic.
if exists = isFile(fl); exists {
return true
}
// It does not exist but may still be a valid filepath.
switch field.Kind() {
case reflect.String:
// Every OS allows for whitespace, but none
// let you use a file with no filename (to my knowledge).
// Unless you're dealing with raw inodes, but I digress.
if strings.TrimSpace(field.String()) == "" {
return false
}
// We make sure it isn't a directory.
if strings.HasSuffix(field.String(), string(os.PathSeparator)) {
return false
}
if _, err = os.Stat(field.String()); err != nil {
switch t := err.(type) {
case *fs.PathError:
if t.Err == syscall.EINVAL {
// It's definitely an invalid character in the filepath.
return false
}
// It could be a permission error, a does-not-exist error, etc.
// Out-of-scope for this validation, though.
return true
default:
// Something went *seriously* wrong.
/*
Per https://pkg.go.dev/os#Stat:
"If there is an error, it will be of type *PathError."
*/
panic(err)
}
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isE164 is the validation function for validating if the current field's value is a valid e.164 formatted phone number.
func isE164(fl FieldLevel) bool {
return e164Regex().MatchString(fl.Field().String())
}
// isEmail is the validation function for validating if the current field's value is a valid email address.
func isEmail(fl FieldLevel) bool {
_, err := mail.ParseAddress(fl.Field().String())
if err != nil {
return false
}
return emailRegex().MatchString(fl.Field().String())
}
// isHSLA is the validation function for validating if the current field's value is a valid HSLA color.
func isHSLA(fl FieldLevel) bool {
return hslaRegex().MatchString(fl.Field().String())
}
// isCMYK is the validation function for validating if the current field's value is a valid CMYK color.
func isCMYK(fl FieldLevel) bool {
return cmykRegex().MatchString(fl.Field().String())
}
// isHSL is the validation function for validating if the current field's value is a valid HSL color.
func isHSL(fl FieldLevel) bool {
return hslRegex().MatchString(fl.Field().String())
}
// isRGBA is the validation function for validating if the current field's value is a valid RGBA color.
func isRGBA(fl FieldLevel) bool {
return rgbaRegex().MatchString(fl.Field().String())
}
// isRGB is the validation function for validating if the current field's value is a valid RGB color.
func isRGB(fl FieldLevel) bool {
return rgbRegex().MatchString(fl.Field().String())
}
// isHEXColor is the validation function for validating if the current field's value is a valid HEX color.
func isHEXColor(fl FieldLevel) bool {
return hexColorRegex().MatchString(fl.Field().String())
}
// isHexadecimal is the validation function for validating if the current field's value is a valid hexadecimal.
func isHexadecimal(fl FieldLevel) bool {
return hexadecimalRegex().MatchString(fl.Field().String())
}
// isNumber is the validation function for validating if the current field's value is a valid number.
func isNumber(fl FieldLevel) bool {
switch fl.Field().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
return true
default:
return numberRegex().MatchString(fl.Field().String())
}
}
// isNumeric is the validation function for validating if the current field's value is a valid numeric value.
func isNumeric(fl FieldLevel) bool {
switch fl.Field().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64:
return true
default:
return numericRegex().MatchString(fl.Field().String())
}
}
// isAlphanum is the validation function for validating if the current field's value is a valid alphanumeric value.
func isAlphanum(fl FieldLevel) bool {
return alphaNumericRegex().MatchString(fl.Field().String())
}
// isAlpha is the validation function for validating if the current field's value is a valid alpha value.
func isAlpha(fl FieldLevel) bool {
return alphaRegex().MatchString(fl.Field().String())
}
// isAlphanumUnicode is the validation function for validating if the current field's value is a valid alphanumeric unicode value.
func isAlphanumUnicode(fl FieldLevel) bool {
return alphaUnicodeNumericRegex().MatchString(fl.Field().String())
}
// isAlphaSpace is the validation function for validating if the current field's value is a valid alpha value with spaces.
func isAlphaSpace(fl FieldLevel) bool {
return alphaSpaceRegex().MatchString(fl.Field().String())
}
// isAlphaNumericSpace is the validation function for validating if the current field's value is a valid alphanumeric value with spaces.
func isAlphaNumericSpace(fl FieldLevel) bool {
return alphanNumericSpaceRegex().MatchString(fl.Field().String())
}
// isAlphaUnicode is the validation function for validating if the current field's value is a valid alpha unicode value.
func isAlphaUnicode(fl FieldLevel) bool {
return alphaUnicodeRegex().MatchString(fl.Field().String())
}
// isBoolean is the validation function for validating if the current field's value is a valid boolean value or can be safely converted to a boolean value.
func isBoolean(fl FieldLevel) bool {
switch fl.Field().Kind() {
case reflect.Bool:
return true
default:
_, err := strconv.ParseBool(fl.Field().String())
return err == nil
}
}
// isDefault is the opposite of required aka hasValue
func isDefault(fl FieldLevel) bool {
return !hasValue(fl)
}
// hasValue is the validation function for validating if the current field's value is not the default static value.
func hasValue(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !field.IsNil()
default:
if fl.(*validate).fldIsPointer && getValue(field) != nil {
return true
}
return field.IsValid() && !field.IsZero()
}
}
// hasNotZeroValue is the validation function for validating if the current field's value is not the zero value for its type.
func hasNotZeroValue(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.Slice, reflect.Map:
// For slices and maps, consider them "not zero" only if they're both non-nil AND have elements
return !field.IsNil() && field.Len() > 0
case reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return !field.IsNil()
default:
if fl.(*validate).fldIsPointer && getValue(field) != nil {
return !field.IsZero()
}
return field.IsValid() && !field.IsZero()
}
}
// requireCheckFieldKind is a func for check field kind
func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundValue bool) bool {
field := fl.Field()
kind := field.Kind()
var nullable, found bool
if len(param) > 0 {
field, kind, nullable, found = fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
if !found {
return defaultNotFoundValue
}
}
switch kind {
case reflect.Invalid:
return defaultNotFoundValue
case reflect.Slice, reflect.Map, reflect.Ptr, reflect.Interface, reflect.Chan, reflect.Func:
return field.IsNil()
default:
if nullable && getValue(field) != nil {
return false
}
return field.IsValid() && field.IsZero()
}
}
// requireCheckFieldValue is a func for check field value
func requireCheckFieldValue(
fl FieldLevel, param string, value string, defaultNotFoundValue bool,
) bool {
field, kind, _, found := fl.GetStructFieldOKAdvanced2(fl.Parent(), param)
if !found {
return defaultNotFoundValue
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() == asInt(value)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() == asUint(value)
case reflect.Float32:
return field.Float() == asFloat32(value)
case reflect.Float64:
return field.Float() == asFloat64(value)
case reflect.Slice, reflect.Map:
if value == "nil" {
return field.IsNil()
}
return int64(field.Len()) == asInt(value)
case reflect.Array:
// Arrays can't be nil, so only compare lengths
return int64(field.Len()) == asInt(value)
case reflect.Bool:
return field.Bool() == (value == "true")
case reflect.Ptr:
if field.IsNil() {
return value == "nil"
}
// Handle non-nil pointers
return requireCheckFieldValue(fl, param, value, defaultNotFoundValue)
}
// default reflect.String:
return field.String() == value
}
// requiredIf is the validation function
// The field under validation must be present and not empty only if all the other specified fields are equal to the value following with the specified field.
func requiredIf(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
if len(params)%2 != 0 {
panic(fmt.Sprintf("Bad param number for required_if %s", fl.FieldName()))
}
seen := make(map[string]struct{})
for i := 0; i < len(params); i += 2 {
if _, ok := seen[params[i]]; ok {
panic(fmt.Sprintf("Duplicate param %s for required_if %s", params[i], fl.FieldName()))
}
seen[params[i]] = struct{}{}
}
for i := 0; i < len(params); i += 2 {
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
return true
}
}
return hasValue(fl)
}
// excludedIf is the validation function
// The field under validation must not be present or is empty only if all the other specified fields are equal to the value following with the specified field.
func excludedIf(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
if len(params)%2 != 0 {
panic(fmt.Sprintf("Bad param number for excluded_if %s", fl.FieldName()))
}
for i := 0; i < len(params); i += 2 {
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
return true
}
}
return !hasValue(fl)
}
// requiredUnless is the validation function
// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
func requiredUnless(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
if len(params)%2 != 0 {
panic(fmt.Sprintf("Bad param number for required_unless %s", fl.FieldName()))
}
for i := 0; i < len(params); i += 2 {
if requireCheckFieldValue(fl, params[i], params[i+1], false) {
return true
}
}
return hasValue(fl)
}
// skipUnless is the validation function
// The field under validation must be present and not empty only unless all the other specified fields are equal to the value following with the specified field.
func skipUnless(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
if len(params)%2 != 0 {
panic(fmt.Sprintf("Bad param number for skip_unless %s", fl.FieldName()))
}
for i := 0; i < len(params); i += 2 {
if !requireCheckFieldValue(fl, params[i], params[i+1], false) {
return true
}
}
return hasValue(fl)
}
// excludedUnless is the validation function
// The field under validation must not be present or is empty unless all the other specified fields are equal to the value following with the specified field.
func excludedUnless(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
if len(params)%2 != 0 {
panic(fmt.Sprintf("Bad param number for excluded_unless %s", fl.FieldName()))
}
for i := 0; i < len(params); i += 2 {
if requireCheckFieldValue(fl, params[i], params[i+1], false) {
return true
}
}
return !hasValue(fl)
}
// excludedWith is the validation function
// The field under validation must not be present or is empty if any of the other specified fields are present.
func excludedWith(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if !requireCheckFieldKind(fl, param, true) {
return !hasValue(fl)
}
}
return true
}
// requiredWith is the validation function
// The field under validation must be present and not empty only if any of the other specified fields are present.
func requiredWith(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if !requireCheckFieldKind(fl, param, true) {
return hasValue(fl)
}
}
return true
}
// excludedWithAll is the validation function
// The field under validation must not be present or is empty if all of the other specified fields are present.
func excludedWithAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if requireCheckFieldKind(fl, param, true) {
return true
}
}
return !hasValue(fl)
}
// requiredWithAll is the validation function
// The field under validation must be present and not empty only if all of the other specified fields are present.
func requiredWithAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if requireCheckFieldKind(fl, param, true) {
return true
}
}
return hasValue(fl)
}
// excludedWithout is the validation function
// The field under validation must not be present or is empty when any of the other specified fields are not present.
func excludedWithout(fl FieldLevel) bool {
if requireCheckFieldKind(fl, strings.TrimSpace(fl.Param()), true) {
return !hasValue(fl)
}
return true
}
// requiredWithout is the validation function
// The field under validation must be present and not empty only when any of the other specified fields are not present.
func requiredWithout(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if requireCheckFieldKind(fl, param, true) {
return hasValue(fl)
}
}
return true
}
// excludedWithoutAll is the validation function
// The field under validation must not be present or is empty when all of the other specified fields are not present.
func excludedWithoutAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if !requireCheckFieldKind(fl, param, true) {
return true
}
}
return !hasValue(fl)
}
// requiredWithoutAll is the validation function
// The field under validation must be present and not empty only when all of the other specified fields are not present.
func requiredWithoutAll(fl FieldLevel) bool {
params := parseOneOfParam2(fl.Param())
for _, param := range params {
if !requireCheckFieldKind(fl, param, true) {
return true
}
}
return hasValue(fl)
}
// isGteField is the validation function for validating if the current field's value is greater than or equal to the field specified by the param's value.
func isGteField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() >= currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() >= currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() >= currentField.Float()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
t := getValue(currentField.Convert(timeType)).(time.Time)
fieldTime := getValue(field.Convert(timeType)).(time.Time)
return fieldTime.After(t) || fieldTime.Equal(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
}
// default reflect.String
return len(field.String()) >= len(currentField.String())
}
// isGtField is the validation function for validating if the current field's value is greater than the field specified by the param's value.
func isGtField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() > currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() > currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() > currentField.Float()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
t := getValue(currentField.Convert(timeType)).(time.Time)
fieldTime := getValue(field.Convert(timeType)).(time.Time)
return fieldTime.After(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
}
// default reflect.String
return len(field.String()) > len(currentField.String())
}
// isGte is the validation function for validating if the current field's value is greater than or equal to the param's value.
func isGte(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) >= p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) >= p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asIntFromType(field.Type(), param)
return field.Int() >= p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() >= p
case reflect.Float32:
p := asFloat32(param)
return field.Float() >= p
case reflect.Float64:
p := asFloat64(param)
return field.Float() >= p
case reflect.Struct:
if field.Type().ConvertibleTo(timeType) {
now := time.Now().UTC()
t := getValue(field.Convert(timeType)).(time.Time)
return t.After(now) || t.Equal(now)
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isGt is the validation function for validating if the current field's value is greater than the param's value.
func isGt(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) > p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) > p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asIntFromType(field.Type(), param)
return field.Int() > p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() > p
case reflect.Float32:
p := asFloat32(param)
return field.Float() > p
case reflect.Float64:
p := asFloat64(param)
return field.Float() > p
case reflect.Struct:
if field.Type().ConvertibleTo(timeType) {
return getValue(field.Convert(timeType)).(time.Time).After(time.Now().UTC())
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// hasLengthOf is the validation function for validating if the current field's value is equal to the param's value.
func hasLengthOf(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) == p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) == p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asIntFromType(field.Type(), param)
return field.Int() == p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() == p
case reflect.Float32:
p := asFloat32(param)
return field.Float() == p
case reflect.Float64:
p := asFloat64(param)
return field.Float() == p
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// hasMinOf is the validation function for validating if the current field's value is greater than or equal to the param's value.
func hasMinOf(fl FieldLevel) bool {
return isGte(fl)
}
// isLteField is the validation function for validating if the current field's value is less than or equal to the field specified by the param's value.
func isLteField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() <= currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() <= currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() <= currentField.Float()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
t := getValue(currentField.Convert(timeType)).(time.Time)
fieldTime := getValue(field.Convert(timeType)).(time.Time)
return fieldTime.Before(t) || fieldTime.Equal(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
}
// default reflect.String
return len(field.String()) <= len(currentField.String())
}
// isLtField is the validation function for validating if the current field's value is less than the field specified by the param's value.
func isLtField(fl FieldLevel) bool {
field := fl.Field()
kind := field.Kind()
currentField, currentKind, ok := fl.GetStructFieldOK()
if !ok || currentKind != kind {
return false
}
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return field.Int() < currentField.Int()
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return field.Uint() < currentField.Uint()
case reflect.Float32, reflect.Float64:
return field.Float() < currentField.Float()
case reflect.Struct:
fieldType := field.Type()
if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) {
t := getValue(currentField.Convert(timeType)).(time.Time)
fieldTime := getValue(field.Convert(timeType)).(time.Time)
return fieldTime.Before(t)
}
// Not Same underlying type i.e. struct and time
if fieldType != currentField.Type() {
return false
}
}
// default reflect.String
return len(field.String()) < len(currentField.String())
}
// isLte is the validation function for validating if the current field's value is less than or equal to the param's value.
func isLte(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) <= p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) <= p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asIntFromType(field.Type(), param)
return field.Int() <= p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() <= p
case reflect.Float32:
p := asFloat32(param)
return field.Float() <= p
case reflect.Float64:
p := asFloat64(param)
return field.Float() <= p
case reflect.Struct:
if field.Type().ConvertibleTo(timeType) {
now := time.Now().UTC()
t := getValue(field.Convert(timeType)).(time.Time)
return t.Before(now) || t.Equal(now)
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isLt is the validation function for validating if the current field's value is less than the param's value.
func isLt(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
switch field.Kind() {
case reflect.String:
p := asInt(param)
return int64(utf8.RuneCountInString(field.String())) < p
case reflect.Slice, reflect.Map, reflect.Array:
p := asInt(param)
return int64(field.Len()) < p
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
p := asIntFromType(field.Type(), param)
return field.Int() < p
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
p := asUint(param)
return field.Uint() < p
case reflect.Float32:
p := asFloat32(param)
return field.Float() < p
case reflect.Float64:
p := asFloat64(param)
return field.Float() < p
case reflect.Struct:
if field.Type().ConvertibleTo(timeType) {
return getValue(field.Convert(timeType)).(time.Time).Before(time.Now().UTC())
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// hasMaxOf is the validation function for validating if the current field's value is less than or equal to the param's value.
func hasMaxOf(fl FieldLevel) bool {
return isLte(fl)
}
// isTCP4AddrResolvable is the validation function for validating if the field's value is a resolvable tcp4 address.
func isTCP4AddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) {
return false
}
_, err := net.ResolveTCPAddr("tcp4", fl.Field().String())
return err == nil
}
// isTCP6AddrResolvable is the validation function for validating if the field's value is a resolvable tcp6 address.
func isTCP6AddrResolvable(fl FieldLevel) bool {
if !isIP6Addr(fl) {
return false
}
_, err := net.ResolveTCPAddr("tcp6", fl.Field().String())
return err == nil
}
// isTCPAddrResolvable is the validation function for validating if the field's value is a resolvable tcp address.
func isTCPAddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) && !isIP6Addr(fl) {
return false
}
_, err := net.ResolveTCPAddr("tcp", fl.Field().String())
return err == nil
}
// isUDP4AddrResolvable is the validation function for validating if the field's value is a resolvable udp4 address.
func isUDP4AddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) {
return false
}
_, err := net.ResolveUDPAddr("udp4", fl.Field().String())
return err == nil
}
// isUDP6AddrResolvable is the validation function for validating if the field's value is a resolvable udp6 address.
func isUDP6AddrResolvable(fl FieldLevel) bool {
if !isIP6Addr(fl) {
return false
}
_, err := net.ResolveUDPAddr("udp6", fl.Field().String())
return err == nil
}
// isUDPAddrResolvable is the validation function for validating if the field's value is a resolvable udp address.
func isUDPAddrResolvable(fl FieldLevel) bool {
if !isIP4Addr(fl) && !isIP6Addr(fl) {
return false
}
_, err := net.ResolveUDPAddr("udp", fl.Field().String())
return err == nil
}
// isIP4AddrResolvable is the validation function for validating if the field's value is a resolvable ip4 address.
func isIP4AddrResolvable(fl FieldLevel) bool {
if !isIPv4(fl) {
return false
}
_, err := net.ResolveIPAddr("ip4", fl.Field().String())
return err == nil
}
// isIP6AddrResolvable is the validation function for validating if the field's value is a resolvable ip6 address.
func isIP6AddrResolvable(fl FieldLevel) bool {
if !isIPv6(fl) {
return false
}
_, err := net.ResolveIPAddr("ip6", fl.Field().String())
return err == nil
}
// isIPAddrResolvable is the validation function for validating if the field's value is a resolvable ip address.
func isIPAddrResolvable(fl FieldLevel) bool {
if !isIP(fl) {
return false
}
_, err := net.ResolveIPAddr("ip", fl.Field().String())
return err == nil
}
// isUnixAddrResolvable is the validation function for validating if the field's value is a resolvable unix address.
func isUnixAddrResolvable(fl FieldLevel) bool {
_, err := net.ResolveUnixAddr("unix", fl.Field().String())
return err == nil
}
// isUnixDomainSocketExists is the validation function for validating if the field's value is an existing Unix domain socket.
// It handles both filesystem-based sockets and Linux abstract sockets.
// It always returns false for Windows.
func isUnixDomainSocketExists(fl FieldLevel) bool {
if runtime.GOOS == "windows" {
return false
}
sockpath := fl.Field().String()
if sockpath == "" {
return false
}
// On Linux, check for abstract sockets (prefixed with @)
if runtime.GOOS == "linux" && strings.HasPrefix(sockpath, "@") {
return isAbstractSocketExists(sockpath)
}
// For filesystem-based sockets, check if the path exists and is a socket
stats, err := os.Stat(sockpath)
if err != nil {
return false
}
return stats.Mode().Type() == fs.ModeSocket
}
// isAbstractSocketExists checks if a Linux abstract socket exists by reading /proc/net/unix.
// Abstract sockets are identified by an @ prefix in human-readable form.
func isAbstractSocketExists(sockpath string) bool {
file, err := os.Open("/proc/net/unix")
if err != nil {
return false
}
defer func() {
_ = file.Close()
}()
scanner := bufio.NewScanner(file)
// Skip the header line
if !scanner.Scan() {
return false
}
// Abstract sockets in /proc/net/unix are represented with @ prefix
// The socket path is the last field in each line
for scanner.Scan() {
line := scanner.Text()
fields := strings.Fields(line)
// The path is the last field (8th field typically)
if len(fields) >= 8 {
path := fields[len(fields)-1]
if path == sockpath {
return true
}
}
}
return false
}
func isIP4Addr(fl FieldLevel) bool {
val := fl.Field().String()
if idx := strings.LastIndex(val, ":"); idx != -1 {
val = val[0:idx]
}
ip := net.ParseIP(val)
return ip != nil && ip.To4() != nil
}
func isIP6Addr(fl FieldLevel) bool {
val := fl.Field().String()
if idx := strings.LastIndex(val, ":"); idx != -1 {
if idx != 0 && val[idx-1:idx] == "]" {
val = val[1 : idx-1]
}
}
ip := net.ParseIP(val)
return ip != nil && ip.To4() == nil
}
func isHostnameRFC952(fl FieldLevel) bool {
return hostnameRegexRFC952().MatchString(fl.Field().String())
}
func isHostnameRFC1123(fl FieldLevel) bool {
return hostnameRegexRFC1123().MatchString(fl.Field().String())
}
func isFQDN(fl FieldLevel) bool {
val := fl.Field().String()
if val == "" {
return false
}
return fqdnRegexRFC1123().MatchString(val)
}
// isDir is the validation function for validating if the current field's value is a valid existing directory.
func isDir(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
fileInfo, err := os.Stat(field.String())
if err != nil {
return false
}
return fileInfo.IsDir()
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isDirPath is the validation function for validating if the current field's value is a valid directory.
func isDirPath(fl FieldLevel) bool {
var exists bool
var err error
field := fl.Field()
// If it exists, it obviously is valid.
// This is done first to avoid code duplication and unnecessary additional logic.
if exists = isDir(fl); exists {
return true
}
// It does not exist but may still be a valid path.
switch field.Kind() {
case reflect.String:
// Every OS allows for whitespace, but none
// let you use a dir with no name (to my knowledge).
// Unless you're dealing with raw inodes, but I digress.
if strings.TrimSpace(field.String()) == "" {
return false
}
if _, err = os.Stat(field.String()); err != nil {
switch t := err.(type) {
case *fs.PathError:
if t.Err == syscall.EINVAL {
// It's definitely an invalid character in the path.
return false
}
// It could be a permission error, a does-not-exist error, etc.
// Out-of-scope for this validation, though.
// Lastly, we make sure it is a directory.
if strings.HasSuffix(field.String(), string(os.PathSeparator)) {
return true
} else {
return false
}
default:
// Something went *seriously* wrong.
/*
Per https://pkg.go.dev/os#Stat:
"If there is an error, it will be of type *PathError."
*/
panic(err)
}
}
// We repeat the check here to make sure it is an explicit directory in case the above os.Stat didn't trigger an error.
if strings.HasSuffix(field.String(), string(os.PathSeparator)) {
return true
} else {
return false
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isJSON is the validation function for validating if the current field's value is a valid json string.
func isJSON(fl FieldLevel) bool {
field := fl.Field()
switch field.Kind() {
case reflect.String:
val := field.String()
return json.Valid([]byte(val))
case reflect.Slice:
fieldType := field.Type()
if fieldType.ConvertibleTo(byteSliceType) {
b := getValue(field.Convert(byteSliceType)).([]byte)
return json.Valid(b)
}
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isJWT is the validation function for validating if the current field's value is a valid JWT string.
func isJWT(fl FieldLevel) bool {
return jWTRegex().MatchString(fl.Field().String())
}
// isHostnamePort validates a <dns>:<port> combination for fields typically used for socket address.
func isHostnamePort(fl FieldLevel) bool {
val := fl.Field().String()
host, port, err := net.SplitHostPort(val)
if err != nil {
return false
}
// Port must be a iny <= 65535.
if portNum, err := strconv.ParseInt(
port, 10, 32,
); err != nil || portNum > 65535 || portNum < 1 {
return false
}
// If host is specified, it should match a DNS name
if host != "" {
return hostnameRegexRFC1123().MatchString(host)
}
return true
}
// IsPort validates if the current field's value represents a valid port
func isPort(fl FieldLevel) bool {
val := fl.Field().Uint()
return val >= 1 && val <= 65535
}
// isLowercase is the validation function for validating if the current field's value is a lowercase string.
func isLowercase(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
if field.String() == "" {
return false
}
return field.String() == strings.ToLower(field.String())
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isUppercase is the validation function for validating if the current field's value is an uppercase string.
func isUppercase(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
if field.String() == "" {
return false
}
return field.String() == strings.ToUpper(field.String())
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isDatetime is the validation function for validating if the current field's value is a valid datetime string.
func isDatetime(fl FieldLevel) bool {
field := fl.Field()
param := fl.Param()
if field.Kind() == reflect.String {
_, err := time.Parse(param, field.String())
return err == nil
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isTimeZone is the validation function for validating if the current field's value is a valid time zone string.
func isTimeZone(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
// empty value is converted to UTC by time.LoadLocation but disallow it as it is not a valid time zone name
if field.String() == "" {
return false
}
// Local value is converted to the current system time zone by time.LoadLocation but disallow it as it is not a valid time zone name
if strings.ToLower(field.String()) == "local" {
return false
}
_, err := time.LoadLocation(field.String())
return err == nil
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isIso3166Alpha2 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 country code.
func isIso3166Alpha2(fl FieldLevel) bool {
_, ok := iso3166_1_alpha2[fl.Field().String()]
return ok
}
// isIso3166Alpha2EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-2 European Union country code.
func isIso3166Alpha2EU(fl FieldLevel) bool {
_, ok := iso3166_1_alpha2_eu[fl.Field().String()]
return ok
}
// isIso3166Alpha3 is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 country code.
func isIso3166Alpha3(fl FieldLevel) bool {
_, ok := iso3166_1_alpha3[fl.Field().String()]
return ok
}
// isIso3166Alpha3EU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-3 European Union country code.
func isIso3166Alpha3EU(fl FieldLevel) bool {
_, ok := iso3166_1_alpha3_eu[fl.Field().String()]
return ok
}
// isIso3166AlphaNumeric is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric country code.
func isIso3166AlphaNumeric(fl FieldLevel) bool {
field := fl.Field()
var code int
switch field.Kind() {
case reflect.String:
i, err := strconv.Atoi(field.String())
if err != nil {
return false
}
code = i % 1000
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
code = int(field.Int() % 1000)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
code = int(field.Uint() % 1000)
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
_, ok := iso3166_1_alpha_numeric[code]
return ok
}
// isIso3166AlphaNumericEU is the validation function for validating if the current field's value is a valid iso3166-1 alpha-numeric European Union country code.
func isIso3166AlphaNumericEU(fl FieldLevel) bool {
field := fl.Field()
var code int
switch field.Kind() {
case reflect.String:
i, err := strconv.Atoi(field.String())
if err != nil {
return false
}
code = i % 1000
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
code = int(field.Int() % 1000)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
code = int(field.Uint() % 1000)
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
_, ok := iso3166_1_alpha_numeric_eu[code]
return ok
}
// isIso31662 is the validation function for validating if the current field's value is a valid iso3166-2 code.
func isIso31662(fl FieldLevel) bool {
_, ok := iso3166_2[fl.Field().String()]
return ok
}
// isIso4217 is the validation function for validating if the current field's value is a valid iso4217 currency code.
func isIso4217(fl FieldLevel) bool {
_, ok := iso4217[fl.Field().String()]
return ok
}
// isIso4217Numeric is the validation function for validating if the current field's value is a valid iso4217 numeric currency code.
func isIso4217Numeric(fl FieldLevel) bool {
field := fl.Field()
var code int
switch field.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
code = int(field.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
code = int(field.Uint())
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
_, ok := iso4217_numeric[code]
return ok
}
// isBCP47LanguageTag is the validation function for validating if the current field's value is a valid BCP 47 language tag, as parsed by language.Parse
func isBCP47LanguageTag(fl FieldLevel) bool {
field := fl.Field()
if field.Kind() == reflect.String {
_, err := language.Parse(field.String())
return err == nil
}
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
// isIsoBic2014Format is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 2014
func isIsoBic2014Format(fl FieldLevel) bool {
bicString := fl.Field().String()
return bic2014Regex().MatchString(bicString)
}
// isIsoBic2022Format is the validation function for validating if the current field's value is a valid Business Identifier Code (SWIFT code), defined in ISO 9362 2022
func isIsoBic2022Format(fl FieldLevel) bool {
bicString := fl.Field().String()
return bic2022Regex().MatchString(bicString)
}
// isSemverFormat is the validation function for validating if the current field's value is a valid semver version, defined in Semantic Versioning 2.0.0
func isSemverFormat(fl FieldLevel) bool {
semverString := fl.Field().String()
return semverRegex().MatchString(semverString)
}
// isCveFormat is the validation function for validating if the current field's value is a valid cve id, defined in CVE mitre org
func isCveFormat(fl FieldLevel) bool {
cveString := fl.Field().String()
return cveRegex().MatchString(cveString)
}
// isDnsRFC1035LabelFormat is the validation function
// for validating if the current field's value is
// a valid dns RFC 1035 label, defined in RFC 1035.
func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
val := fl.Field().String()
size := len(val)
if size > 63 {
return false
}
return dnsRegexRFC1035Label().MatchString(val)
}
// digitsHaveLuhnChecksum returns true if and only if the last element of the given digits slice is the Luhn checksum of the previous elements
func digitsHaveLuhnChecksum(digits []string) bool {
size := len(digits)
sum := 0
for i, digit := range digits {
value, err := strconv.Atoi(digit)
if err != nil {
return false
}
if size%2 == 0 && i%2 == 0 || size%2 == 1 && i%2 == 1 {
v := value * 2
if v >= 10 {
sum += 1 + (v % 10)
} else {
sum += v
}
} else {
sum += value
}
}
return (sum % 10) == 0
}
// isMongoDBObjectId is the validation function for validating if the current field's value is valid MongoDB ObjectID
func isMongoDBObjectId(fl FieldLevel) bool {
val := fl.Field().String()
return mongodbIdRegex().MatchString(val)
}
// isMongoDBConnectionString is the validation function for validating if the current field's value is valid MongoDB Connection String
func isMongoDBConnectionString(fl FieldLevel) bool {
val := fl.Field().String()
return mongodbConnectionRegex().MatchString(val)
}
// isSpiceDB is the validation function for validating if the current field's value is valid for use with Authzed SpiceDB in the indicated way
func isSpiceDB(fl FieldLevel) bool {
val := fl.Field().String()
param := fl.Param()
switch param {
case "permission":
return spicedbPermissionRegex().MatchString(val)
case "type":
return spicedbTypeRegex().MatchString(val)
case "id", "":
return spicedbIDRegex().MatchString(val)
}
panic("Unrecognized parameter: " + param)
}
// isCreditCard is the validation function for validating if the current field's value is a valid credit card number
func isCreditCard(fl FieldLevel) bool {
val := fl.Field().String()
var creditCard bytes.Buffer
segments := strings.Split(val, " ")
for _, segment := range segments {
if len(segment) < 3 {
return false
}
creditCard.WriteString(segment)
}
ccDigits := strings.Split(creditCard.String(), "")
size := len(ccDigits)
if size < 12 || size > 19 {
return false
}
return digitsHaveLuhnChecksum(ccDigits)
}
// hasLuhnChecksum is the validation for validating if the current field's value has a valid Luhn checksum
func hasLuhnChecksum(fl FieldLevel) bool {
field := fl.Field()
var str string // convert to a string which will then be split into single digits; easier and more readable than shifting/extracting single digits from a number
switch field.Kind() {
case reflect.String:
str = field.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
str = strconv.FormatInt(field.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
str = strconv.FormatUint(field.Uint(), 10)
default:
panic(fmt.Sprintf("Bad field type %s", field.Type()))
}
size := len(str)
if size < 2 { // there has to be at least one digit that carries a meaning + the checksum
return false
}
digits := strings.Split(str, "")
return digitsHaveLuhnChecksum(digits)
}
// isCron is the validation function for validating if the current field's value is a valid cron expression
func isCron(fl FieldLevel) bool {
cronString := fl.Field().String()
return cronRegex().MatchString(cronString)
}
// isEIN is the validation function for validating if the current field's value is a valid U.S. Employer Identification Number (EIN)
func isEIN(fl FieldLevel) bool {
field := fl.Field()
if field.Len() != 10 {
return false
}
return einRegex().MatchString(field.String())
}
func isValidateFn(fl FieldLevel) bool {
const defaultParam = `Validate`
field := fl.Field()
validateFn := cmp.Or(fl.Param(), defaultParam)
ok, err := tryCallValidateFn(field, validateFn)
if err != nil {
return false
}
return ok
}
var (
errMethodNotFound = errors.New(`method not found`)
errMethodReturnNoValues = errors.New(`method return o values (void)`)
errMethodReturnInvalidType = errors.New(`method should return invalid type`)
)
func tryCallValidateFn(field reflect.Value, validateFn string) (bool, error) {
method := field.MethodByName(validateFn)
if field.CanAddr() && !method.IsValid() {
method = field.Addr().MethodByName(validateFn)
}
if !method.IsValid() {
return false, fmt.Errorf("unable to call %q on type %q: %w",
validateFn, field.Type().String(), errMethodNotFound)
}
returnValues := method.Call([]reflect.Value{})
if len(returnValues) == 0 {
return false, fmt.Errorf("unable to use result of method %q on type %q: %w",
validateFn, field.Type().String(), errMethodReturnNoValues)
}
firstReturnValue := returnValues[0]
switch firstReturnValue.Kind() {
case reflect.Bool:
return firstReturnValue.Bool(), nil
case reflect.Interface:
errorType := reflect.TypeOf((*error)(nil)).Elem()
if firstReturnValue.Type().Implements(errorType) {
return firstReturnValue.IsNil(), nil
}
return false, fmt.Errorf("unable to use result of method %q on type %q: %w (got interface %v expect error)",
validateFn, field.Type().String(), errMethodReturnInvalidType, firstReturnValue.Type().String())
default:
return false, fmt.Errorf("unable to use result of method %q on type %q: %w (got %v expect error or bool)",
validateFn, field.Type().String(), errMethodReturnInvalidType, firstReturnValue.Type().String())
}
}
================================================
FILE: benchmarks_test.go
================================================
package validator
import (
"bytes"
sql "database/sql/driver"
"errors"
"testing"
"time"
)
func BenchmarkFieldSuccess(b *testing.B) {
validate := New()
s := "1"
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(&s, "len=1")
}
}
func BenchmarkFieldSuccessParallel(b *testing.B) {
validate := New()
s := "1"
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(&s, "len=1")
}
})
}
func BenchmarkFieldFailure(b *testing.B) {
validate := New()
s := "12"
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(&s, "len=1")
}
}
func BenchmarkFieldFailureParallel(b *testing.B) {
validate := New()
s := "12"
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(&s, "len=1")
}
})
}
func BenchmarkFieldArrayDiveSuccess(b *testing.B) {
validate := New()
m := []string{"val1", "val2", "val3"}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,required")
}
}
func BenchmarkFieldArrayDiveSuccessParallel(b *testing.B) {
validate := New()
m := []string{"val1", "val2", "val3"}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(m, "required,dive,required")
}
})
}
func BenchmarkFieldArrayDiveFailure(b *testing.B) {
validate := New()
m := []string{"val1", "", "val3"}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,required")
}
}
func BenchmarkFieldArrayDiveFailureParallel(b *testing.B) {
validate := New()
m := []string{"val1", "", "val3"}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(m, "required,dive,required")
}
})
}
func BenchmarkFieldMapDiveSuccess(b *testing.B) {
validate := New()
m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,required")
}
}
func BenchmarkFieldMapDiveSuccessParallel(b *testing.B) {
validate := New()
m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(m, "required,dive,required")
}
})
}
func BenchmarkFieldMapDiveFailure(b *testing.B) {
validate := New()
m := map[string]string{"": "", "val3": "val3"}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,required")
}
}
func BenchmarkFieldMapDiveFailureParallel(b *testing.B) {
validate := New()
m := map[string]string{"": "", "val3": "val3"}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(m, "required,dive,required")
}
})
}
func BenchmarkFieldMapDiveWithKeysSuccess(b *testing.B) {
validate := New()
m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,keys,required,endkeys,required")
}
}
func BenchmarkFieldMapDiveWithKeysSuccessParallel(b *testing.B) {
validate := New()
m := map[string]string{"val1": "val1", "val2": "val2", "val3": "val3"}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(m, "required,dive,keys,required,endkeys,required")
}
})
}
func BenchmarkFieldMapDiveWithKeysFailure(b *testing.B) {
validate := New()
m := map[string]string{"": "", "val3": "val3"}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(m, "required,dive,keys,required,endkeys,required")
}
}
func BenchmarkFieldMapDiveWithKeysFailureParallel(b *testing.B) {
validate := New()
m := map[string]string{"": "", "val3": "val3"}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(m, "required,dive,keys,required,endkeys,required")
}
})
}
func BenchmarkFieldCustomTypeSuccess(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{
Name: "1",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(val, "len=1")
}
}
func BenchmarkFieldCustomTypeSuccessParallel(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{
Name: "1",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(val, "len=1")
}
})
}
func BenchmarkFieldCustomTypeFailure(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(val, "len=1")
}
}
func BenchmarkFieldCustomTypeFailureParallel(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(val, "len=1")
}
})
}
func BenchmarkFieldOrTagSuccess(b *testing.B) {
validate := New()
s := "rgba(0,0,0,1)"
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(s, "rgb|rgba")
}
}
func BenchmarkFieldOrTagSuccessParallel(b *testing.B) {
validate := New()
s := "rgba(0,0,0,1)"
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(s, "rgb|rgba")
}
})
}
func BenchmarkFieldOrTagFailure(b *testing.B) {
validate := New()
s := "#000"
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Var(s, "rgb|rgba")
}
}
func BenchmarkFieldOrTagFailureParallel(b *testing.B) {
validate := New()
s := "#000"
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Var(s, "rgb|rgba")
}
})
}
func BenchmarkStructLevelValidationSuccess(b *testing.B) {
validate := New()
validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{})
tst := TestStruct{
String: "good value",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(tst)
}
}
func BenchmarkStructLevelValidationSuccessParallel(b *testing.B) {
validate := New()
validate.RegisterStructValidation(StructValidationTestStructSuccess, TestStruct{})
tst := TestStruct{
String: "good value",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(tst)
}
})
}
func BenchmarkStructLevelValidationFailure(b *testing.B) {
validate := New()
validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{})
tst := TestStruct{
String: "good value",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(tst)
}
}
func BenchmarkStructLevelValidationFailureParallel(b *testing.B) {
validate := New()
validate.RegisterStructValidation(StructValidationTestStruct, TestStruct{})
tst := TestStruct{
String: "good value",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(tst)
}
})
}
func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{
Name: "1",
}
type Foo struct {
Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"`
}
validFoo := &Foo{Valuer: val, IntValue: 7}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(validFoo)
}
}
func BenchmarkStructSimpleCustomTypeSuccessParallel(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{
Name: "1",
}
type Foo struct {
Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"`
}
validFoo := &Foo{Valuer: val, IntValue: 7}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(validFoo)
}
})
}
func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{}
type Foo struct {
Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"`
}
validFoo := &Foo{Valuer: val, IntValue: 3}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(validFoo)
}
}
func BenchmarkStructSimpleCustomTypeFailureParallel(b *testing.B) {
validate := New()
validate.RegisterCustomTypeFunc(ValidateValuerType, (*sql.Valuer)(nil), valuer{})
val := valuer{}
type Foo struct {
Valuer valuer `validate:"len=1"`
IntValue int `validate:"min=5,max=10"`
}
validFoo := &Foo{Valuer: val, IntValue: 3}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(validate.Struct(validFoo))
}
})
}
func BenchmarkStructFilteredSuccess(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
byts := []byte("Name")
fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.StructFiltered(test, fn)
}
}
func BenchmarkStructFilteredSuccessParallel(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
byts := []byte("Name")
fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts)
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.StructFiltered(test, fn)
}
})
}
func BenchmarkStructFilteredFailure(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
byts := []byte("NickName")
fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts)
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.StructFiltered(test, fn)
}
}
func BenchmarkStructFilteredFailureParallel(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
byts := []byte("NickName")
fn := func(ns []byte) bool {
return !bytes.HasSuffix(ns, byts)
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.StructFiltered(test, fn)
}
})
}
func BenchmarkStructPartialSuccess(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.StructPartial(test, "Name")
}
}
func BenchmarkStructPartialSuccessParallel(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.StructPartial(test, "Name")
}
})
}
func BenchmarkStructPartialFailure(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.StructPartial(test, "NickName")
}
}
func BenchmarkStructPartialFailureParallel(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.StructPartial(test, "NickName")
}
})
}
func BenchmarkStructExceptSuccess(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.StructExcept(test, "Nickname")
}
}
func BenchmarkStructExceptSuccessParallel(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.StructExcept(test, "NickName")
}
})
}
func BenchmarkStructExceptFailure(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.StructExcept(test, "Name")
}
}
func BenchmarkStructExceptFailureParallel(b *testing.B) {
validate := New()
type Test struct {
Name string `validate:"required"`
NickName string `validate:"required"`
}
test := &Test{
Name: "Joey Bloggs",
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.StructExcept(test, "Name")
}
})
}
func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) {
validate := New()
type Test struct {
Start time.Time
End time.Time `validate:"gtfield=Start"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
test := &Test{
Start: now,
End: then,
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(test)
}
}
func BenchmarkStructSimpleCrossFieldSuccessParallel(b *testing.B) {
validate := New()
type Test struct {
Start time.Time
End time.Time `validate:"gtfield=Start"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
test := &Test{
Start: now,
End: then,
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(test)
}
})
}
func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) {
validate := New()
type Test struct {
Start time.Time
End time.Time `validate:"gtfield=Start"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * -5)
test := &Test{
Start: now,
End: then,
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(test)
}
}
func BenchmarkStructSimpleCrossFieldFailureParallel(b *testing.B) {
validate := New()
type Test struct {
Start time.Time
End time.Time `validate:"gtfield=Start"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * -5)
test := &Test{
Start: now,
End: then,
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(test)
}
})
}
func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) {
validate := New()
type Inner struct {
Start time.Time
}
type Outer struct {
Inner *Inner
CreatedAt time.Time `validate:"eqcsfield=Inner.Start"`
}
now := time.Now().UTC()
inner := &Inner{
Start: now,
}
outer := &Outer{
Inner: inner,
CreatedAt: now,
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(outer)
}
}
func BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel(b *testing.B) {
validate := New()
type Inner struct {
Start time.Time
}
type Outer struct {
Inner *Inner
CreatedAt time.Time `validate:"eqcsfield=Inner.Start"`
}
now := time.Now().UTC()
inner := &Inner{
Start: now,
}
outer := &Outer{
Inner: inner,
CreatedAt: now,
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(outer)
}
})
}
func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) {
validate := New()
type Inner struct {
Start time.Time
}
type Outer struct {
Inner *Inner
CreatedAt time.Time `validate:"eqcsfield=Inner.Start"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
inner := &Inner{
Start: then,
}
outer := &Outer{
Inner: inner,
CreatedAt: now,
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(outer)
}
}
func BenchmarkStructSimpleCrossStructCrossFieldFailureParallel(b *testing.B) {
validate := New()
type Inner struct {
Start time.Time
}
type Outer struct {
Inner *Inner
CreatedAt time.Time `validate:"eqcsfield=Inner.Start"`
}
now := time.Now().UTC()
then := now.Add(time.Hour * 5)
inner := &Inner{
Start: then,
}
outer := &Outer{
Inner: inner,
CreatedAt: now,
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(outer)
}
})
}
func BenchmarkStructSimpleSuccess(b *testing.B) {
validate := New()
type Foo struct {
StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"`
}
validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(validFoo)
}
}
func BenchmarkStructSimpleSuccessParallel(b *testing.B) {
validate := New()
type Foo struct {
StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"`
}
validFoo := &Foo{StringValue: "Foobar", IntValue: 7}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(validFoo)
}
})
}
func BenchmarkStructSimpleFailure(b *testing.B) {
validate := New()
type Foo struct {
StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"`
}
invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(invalidFoo)
}
}
func BenchmarkStructSimpleFailureParallel(b *testing.B) {
validate := New()
type Foo struct {
StringValue string `validate:"min=5,max=10"`
IntValue int `validate:"min=5,max=10"`
}
invalidFoo := &Foo{StringValue: "Fo", IntValue: 3}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(invalidFoo)
}
})
}
func BenchmarkStructComplexSuccess(b *testing.B) {
validate := New()
tSuccess := &TestString{
Required: "Required",
Len: "length==10",
Min: "min=1",
Max: "1234567890",
MinMax: "12345",
Lt: "012345678",
Lte: "0123456789",
Gt: "01234567890",
Gte: "0123456789",
OmitEmpty: "",
Sub: &SubTest{
Test: "1",
},
SubIgnore: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
}{
A: "1",
},
Iface: &Impl{
F: "123",
},
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(tSuccess)
}
}
func BenchmarkStructComplexSuccessParallel(b *testing.B) {
validate := New()
tSuccess := &TestString{
Required: "Required",
Len: "length==10",
Min: "min=1",
Max: "1234567890",
MinMax: "12345",
Lt: "012345678",
Lte: "0123456789",
Gt: "01234567890",
Gte: "0123456789",
OmitEmpty: "",
Sub: &SubTest{
Test: "1",
},
SubIgnore: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
}{
A: "1",
},
Iface: &Impl{
F: "123",
},
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(tSuccess)
}
})
}
func BenchmarkStructComplexFailure(b *testing.B) {
validate := New()
tFail := &TestString{
Required: "",
Len: "",
Min: "",
Max: "12345678901",
MinMax: "",
Lt: "0123456789",
Lte: "01234567890",
Gt: "1",
Gte: "1",
OmitEmpty: "12345678901",
Sub: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
}{
A: "",
},
Iface: &Impl{
F: "12",
},
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(tFail)
}
}
func BenchmarkStructComplexFailureParallel(b *testing.B) {
validate := New()
tFail := &TestString{
Required: "",
Len: "",
Min: "",
Max: "12345678901",
MinMax: "",
Lt: "0123456789",
Lte: "01234567890",
Gt: "1",
Gte: "1",
OmitEmpty: "12345678901",
Sub: &SubTest{
Test: "",
},
Anonymous: struct {
A string `validate:"required"`
}{
A: "",
},
Iface: &Impl{
F: "12",
},
}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(tFail)
}
})
}
type TestOneof struct {
Color string `validate:"oneof=red green"`
}
func BenchmarkOneof(b *testing.B) {
w := &TestOneof{Color: "green"}
val := New()
for i := 0; i < b.N; i++ {
_ = val.Struct(w)
}
}
func BenchmarkOneofParallel(b *testing.B) {
w := &TestOneof{Color: "green"}
val := New()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = val.Struct(w)
}
})
}
type T struct{}
func (*T) Validate() error { return errors.New("ops") }
func BenchmarkValidateFnSequential(b *testing.B) {
validate := New()
type Test struct {
T T `validate:"validateFn"`
}
test := &Test{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
_ = validate.Struct(test)
}
}
func BenchmarkValidateFnParallel(b *testing.B) {
validate := New()
type Test struct {
T T `validate:"validateFn"`
}
test := &Test{}
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = validate.Struct(test)
}
})
}
================================================
FILE: cache.go
================================================
package validator
import (
"fmt"
"reflect"
"strings"
"sync"
"sync/atomic"
)
type tagType uint8
const (
typeDefault tagType = iota
typeOmitEmpty
typeIsDefault
typeNoStructLevel
typeStructOnly
typeDive
typeOr
typeKeys
typeEndKeys
typeOmitNil
typeOmitZero
)
const (
invalidValidation = "Invalid validation tag on field '%s'"
undefinedValidation = "Undefined validation function '%s' on field '%s'"
keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a corresponding '" + keysTag + "' tag"
)
type structCache struct {
lock sync.Mutex
m atomic.Value // map[reflect.Type]*cStruct
}
func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) {
c, found = sc.m.Load().(map[reflect.Type]*cStruct)[key]
return
}
func (sc *structCache) Set(key reflect.Type, value *cStruct) {
m := sc.m.Load().(map[reflect.Type]*cStruct)
nm := make(map[reflect.Type]*cStruct, len(m)+1)
for k, v := range m {
nm[k] = v
}
nm[key] = value
sc.m.Store(nm)
}
type tagCache struct {
lock sync.Mutex
m atomic.Value // map[string]*cTag
}
func (tc *tagCache) Get(key string) (c *cTag, found bool) {
c, found = tc.m.Load().(map[string]*cTag)[key]
return
}
func (tc *tagCache) Set(key string, value *cTag) {
m := tc.m.Load().(map[string]*cTag)
nm := make(map[string]*cTag, len(m)+1)
for k, v := range m {
nm[k] = v
}
nm[key] = value
tc.m.Store(nm)
}
type cStruct struct {
name string
fields []*cField
fn StructLevelFuncCtx
}
type cField struct {
idx int
name string
altName string
namesEqual bool
cTags *cTag
}
type cTag struct {
tag string
aliasTag string
actualAliasTag string
param string
keys *cTag // only populated when using tag's 'keys' and 'endkeys' for map key validation
next *cTag
fn FuncCtx
typeof tagType
hasTag bool
hasAlias bool
hasParam bool // true if parameter used eg. eq= where the equal sign has been set
isBlockEnd bool // indicates the current tag represents the last validation in the block
runValidationWhenNil bool
}
func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStruct {
v.structCache.lock.Lock()
defer v.structCache.lock.Unlock() // leave as defer! because if inner panics, it will never get unlocked otherwise!
typ := current.Type()
// could have been multiple trying to access, but once first is done this ensures struct
// isn't parsed again.
cs, ok := v.structCache.Get(typ)
if ok {
return cs
}
cs = &cStruct{name: sName, fields: make([]*cField, 0), fn: v.structLevelFuncs[typ]}
numFields := current.NumField()
rules := v.rules[typ]
var ctag *cTag
var fld reflect.StructField
var tag string
var customName string
for i := 0; i < numFields; i++ {
fld = typ.Field(i)
if !v.privateFieldValidation && !fld.Anonymous && len(fld.PkgPath) > 0 {
continue
}
if rtag, ok := rules[fld.Name]; ok {
tag = rtag
} else {
tag = fld.Tag.Get(v.tagName)
}
if tag == skipValidationTag {
continue
}
customName = fld.Name
if v.hasTagNameFunc {
name := v.tagNameFunc(fld)
if len(name) > 0 {
customName = name
}
}
// NOTE: cannot use shared tag cache, because tags may be equal, but things like alias may be different
// and so only struct level caching can be used instead of combined with Field tag caching
if len(tag) > 0 {
ctag, _ = v.parseFieldTagsRecursive(tag, fld.Name, "", false)
} else {
// even if field doesn't have validations need cTag for traversing to potential inner/nested
// elements of the field.
ctag = new(cTag)
}
cs.fields = append(cs.fields, &cField{
idx: i,
name: fld.Name,
altName: customName,
cTags: ctag,
namesEqual: fld.Name == customName,
})
}
v.structCache.Set(typ, cs)
return cs
}
func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias string, hasAlias bool) (firstCtag *cTag, current *cTag) {
var t string
noAlias := len(alias) == 0
tags := strings.Split(tag, tagSeparator)
for i := 0; i < len(tags); i++ {
t = tags[i]
if noAlias {
alias = t
}
// check map for alias and process new tags, otherwise process as usual
if tagsVal, found := v.aliases[t]; found {
if i == 0 {
firstCtag, current = v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
} else {
next, curr := v.parseFieldTagsRecursive(tagsVal, fieldName, t, true)
current.next, current = next, curr
}
continue
}
var prevTag tagType
if i == 0 {
current = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true, typeof: typeDefault}
firstCtag = current
} else {
prevTag = current.typeof
current.next = &cTag{aliasTag: alias, hasAlias: hasAlias, hasTag: true}
current = current.next
}
switch t {
case diveTag:
current.typeof = typeDive
case keysTag:
current.typeof = typeKeys
if i == 0 || prevTag != typeDive {
panic(fmt.Sprintf("'%s' tag must be immediately preceded by the '%s' tag", keysTag, diveTag))
}
// need to pass along only keys tag
// need to increment i to skip over the keys tags
b := make([]byte, 0, 64)
i++
for ; i < len(tags); i++ {
b = append(b, tags[i]...)
b = append(b, ',')
if tags[i] == endKeysTag {
break
}
}
current.keys, _ = v.parseFieldTagsRecursive(string(b[:len(b)-1]), fieldName, "", false)
case endKeysTag:
current.typeof = typeEndKeys
// if there are more in tags then there was no keysTag defined
// and an error should be thrown
if i != len(tags)-1 {
panic(keysTagNotDefined)
}
return
case omitzero:
current.typeof = typeOmitZero
continue
case omitempty:
current.typeof = typeOmitEmpty
case omitnil:
current.typeof = typeOmitNil
case structOnlyTag:
current.typeof = typeStructOnly
case noStructLevelTag:
current.typeof = typeNoStructLevel
default:
if t == isdefault {
current.typeof = typeIsDefault
}
// if a pipe character is needed within the param you must use the utf8Pipe representation "0x7C"
orVals := strings.Split(t, orSeparator)
for j := 0; j < len(orVals); j++ {
vals := strings.SplitN(orVals[j], tagKeySeparator, 2)
if noAlias {
alias = vals[0]
current.aliasTag = alias
} else {
current.actualAliasTag = t
}
if j > 0 {
current.next = &cTag{aliasTag: alias, actualAliasTag: current.actualAliasTag, hasAlias: hasAlias, hasTag: true}
current = current.next
}
current.hasParam = len(vals) > 1
current.tag = vals[0]
if len(current.tag) == 0 {
panic(strings.TrimSpace(fmt.Sprintf(invalidValidation, fieldName)))
}
if wrapper, ok := v.validations[current.tag]; ok {
current.fn = wrapper.fn
current.runValidationWhenNil = wrapper.runValidationOnNil
} else if aliasTag, isAlias := v.aliases[current.tag]; isAlias {
aliasFirst, aliasLast := v.parseFieldTagsRecursive(aliasTag, fieldName, current.tag, true)
current.tag = aliasFirst.tag
current.fn = aliasFirst.fn
current.runValidationWhenNil = aliasFirst.runValidationWhenNil
current.hasParam = aliasFirst.hasParam
current.param = aliasFirst.param
current.typeof = aliasFirst.typeof
current.hasAlias = true
if aliasFirst.next != nil {
nextInChain := current.next
current.next = aliasFirst.next
aliasLast.next = nextInChain
aliasLast.isBlockEnd = false
current = aliasLast
}
} else {
panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, current.tag, fieldName)))
}
if len(orVals) > 1 {
current.typeof = typeOr
}
if len(vals) > 1 {
current.param = strings.ReplaceAll(strings.ReplaceAll(vals[1], utf8HexComma, ","), utf8Pipe, "|")
}
}
current.isBlockEnd = true
}
}
return
}
func (v *Validate) fetchCacheTag(tag string) *cTag {
// find cached tag
ctag, found := v.tagCache.Get(tag)
if !found {
v.tagCache.lock.Lock()
defer v.tagCache.lock.Unlock()
// could have been multiple trying to access, but once first is done this ensures tag
// isn't parsed again.
ctag, found = v.tagCache.Get(tag)
if !found {
ctag, _ = v.parseFieldTagsRecursive(tag, "", "", false)
v.tagCache.Set(tag, ctag)
}
}
return ctag
}
================================================
FILE: country_codes.go
================================================
package validator
var iso3166_1_alpha2 = map[string]struct{}{
// see: https://www.iso.org/iso-3166-country-codes.html
"AF": {}, "AX": {}, "AL": {}, "DZ": {}, "AS": {},
"AD": {}, "AO": {}, "AI": {}, "AQ": {}, "AG": {},
"AR": {}, "AM": {}, "AW": {}, "AU": {}, "AT": {},
"AZ": {}, "BS": {}, "BH": {}, "BD": {}, "BB": {},
"BY": {}, "BE": {}, "BZ": {}, "BJ": {}, "BM": {},
"BT": {}, "BO": {}, "BQ": {}, "BA": {}, "BW": {},
"BV": {}, "BR": {}, "IO": {}, "BN": {}, "BG": {},
"BF": {}, "BI": {}, "KH": {}, "CM": {}, "CA": {},
"CV": {}, "KY": {}, "CF": {}, "TD": {}, "CL": {},
"CN": {}, "CX": {}, "CC": {}, "CO": {}, "KM": {},
"CG": {}, "CD": {}, "CK": {}, "CR": {}, "CI": {},
"HR": {}, "CU": {}, "CW": {}, "CY": {}, "CZ": {},
"DK": {}, "DJ": {}, "DM": {}, "DO": {}, "EC": {},
"EG": {}, "SV": {}, "GQ": {}, "ER": {}, "EE": {},
"ET": {}, "FK": {}, "FO": {}, "FJ": {}, "FI": {},
"FR": {}, "GF": {}, "PF": {}, "TF": {}, "GA": {},
"GM": {}, "GE": {}, "DE": {}, "GH": {}, "GI": {},
"GR": {}, "GL": {}, "GD": {}, "GP": {}, "GU": {},
"GT": {}, "GG": {}, "GN": {}, "GW": {}, "GY": {},
"HT": {}, "HM": {}, "VA": {}, "HN": {}, "HK": {},
"HU": {}, "IS": {}, "IN": {}, "ID": {}, "IR": {},
"IQ": {}, "IE": {}, "IM": {}, "IL": {}, "IT": {},
"JM": {}, "JP": {}, "JE": {}, "JO": {}, "KZ": {},
"KE": {}, "KI": {}, "KP": {}, "KR": {}, "KW": {},
"KG": {}, "LA": {}, "LV": {}, "LB": {}, "LS": {},
"LR": {}, "LY": {}, "LI": {}, "LT": {}, "LU": {},
"MO": {}, "MK": {}, "MG": {}, "MW": {}, "MY": {},
"MV": {}, "ML": {}, "MT": {}, "MH": {}, "MQ": {},
"MR": {}, "MU": {}, "YT": {}, "MX": {}, "FM": {},
"MD": {}, "MC": {}, "MN": {}, "ME": {}, "MS": {},
"MA": {}, "MZ": {}, "MM": {}, "NA": {}, "NR": {},
"NP": {}, "NL": {}, "NC": {}, "NZ": {}, "NI": {},
"NE": {}, "NG": {}, "NU": {}, "NF": {}, "MP": {},
"NO": {}, "OM": {}, "PK": {}, "PW": {}, "PS": {},
"PA": {}, "PG": {}, "PY": {}, "PE": {}, "PH": {},
"PN": {}, "PL": {}, "PT": {}, "PR": {}, "QA": {},
"RE": {}, "RO": {}, "RU": {}, "RW": {}, "BL": {},
"SH": {}, "KN": {}, "LC": {}, "MF": {}, "PM": {},
"VC": {}, "WS": {}, "SM": {}, "ST": {}, "SA": {},
"SN": {}, "RS": {}, "SC": {}, "SL": {}, "SG": {},
"SX": {}, "SK": {}, "SI": {}, "SB": {}, "SO": {},
"ZA": {}, "GS": {}, "SS": {}, "ES": {}, "LK": {},
"SD": {}, "SR": {}, "SJ": {}, "SZ": {}, "SE": {},
"CH": {}, "SY": {}, "TW": {}, "TJ": {}, "TZ": {},
"TH": {}, "TL": {}, "TG": {}, "TK": {}, "TO": {},
"TT": {}, "TN": {}, "TR": {}, "TM": {}, "TC": {},
"TV": {}, "UG": {}, "UA": {}, "AE": {}, "GB": {},
"US": {}, "UM": {}, "UY": {}, "UZ": {}, "VU": {},
"VE": {}, "VN": {}, "VG": {}, "VI": {}, "WF": {},
"EH": {}, "YE": {}, "ZM": {}, "ZW": {}, "XK": {},
}
var iso3166_1_alpha2_eu = map[string]struct{}{
"AT": {}, "BE": {}, "BG": {}, "HR": {}, "CY": {},
"CZ": {}, "DK": {}, "EE": {}, "FI": {}, "FR": {},
"DE": {}, "GR": {}, "HU": {}, "IE": {}, "IT": {},
"LV": {}, "LT": {}, "LU": {}, "MT": {}, "NL": {},
"PL": {}, "PT": {}, "RO": {}, "SK": {}, "SI": {},
"ES": {}, "SE": {},
}
var iso3166_1_alpha3 = map[string]struct{}{
// see: https://www.iso.org/iso-3166-country-codes.html
"AFG": {}, "ALB": {}, "DZA": {}, "ASM": {}, "AND": {},
"AGO": {}, "AIA": {}, "ATA": {}, "ATG": {}, "ARG": {},
"ARM": {}, "ABW": {}, "AUS": {}, "AUT": {}, "AZE": {},
"BHS": {}, "BHR": {}, "BGD": {}, "BRB": {}, "BLR": {},
"BEL": {}, "BLZ": {}, "BEN": {}, "BMU": {}, "BTN": {},
"BOL": {}, "BES": {}, "BIH": {}, "BWA": {}, "BVT": {},
"BRA": {}, "IOT": {}, "BRN": {}, "BGR": {}, "BFA": {},
"BDI": {}, "CPV": {}, "KHM": {}, "CMR": {}, "CAN": {},
"CYM": {}, "CAF": {}, "TCD": {}, "CHL": {}, "CHN": {},
"CXR": {}, "CCK": {}, "COL": {}, "COM": {}, "COD": {},
"COG": {}, "COK": {}, "CRI": {}, "HRV": {}, "CUB": {},
"CUW": {}, "CYP": {}, "CZE": {}, "CIV": {}, "DNK": {},
"DJI": {}, "DMA": {}, "DOM": {}, "ECU": {}, "EGY": {},
"SLV": {}, "GNQ": {}, "ERI": {}, "EST": {}, "SWZ": {},
"ETH": {}, "FLK": {}, "FRO": {}, "FJI": {}, "FIN": {},
"FRA": {}, "GUF": {}, "PYF": {}, "ATF": {}, "GAB": {},
"GMB": {}, "GEO": {}, "DEU": {}, "GHA": {}, "GIB": {},
"GRC": {}, "GRL": {}, "GRD": {}, "GLP": {}, "GUM": {},
"GTM": {}, "GGY": {}, "GIN": {}, "GNB": {}, "GUY": {},
"HTI": {}, "HMD": {}, "VAT": {}, "HND": {}, "HKG": {},
"HUN": {}, "ISL": {}, "IND": {}, "IDN": {}, "IRN": {},
"IRQ": {}, "IRL": {}, "IMN": {}, "ISR": {}, "ITA": {},
"JAM": {}, "JPN": {}, "JEY": {}, "JOR": {}, "KAZ": {},
"KEN": {}, "KIR": {}, "PRK": {}, "KOR": {}, "KWT": {},
"KGZ": {}, "LAO": {}, "LVA": {}, "LBN": {}, "LSO": {},
"LBR": {}, "LBY": {}, "LIE": {}, "LTU": {}, "LUX": {},
"MAC": {}, "MDG": {}, "MWI": {}, "MYS": {}, "MDV": {},
"MLI": {}, "MLT": {}, "MHL": {}, "MTQ": {}, "MRT": {},
"MUS": {}, "MYT": {}, "MEX": {}, "FSM": {}, "MDA": {},
"MCO": {}, "MNG": {}, "MNE": {}, "MSR": {}, "MAR": {},
"MOZ": {}, "MMR": {}, "NAM": {}, "NRU": {}, "NPL": {},
"NLD": {}, "NCL": {}, "NZL": {}, "NIC": {}, "NER": {},
"NGA": {}, "NIU": {}, "NFK": {}, "MKD": {}, "MNP": {},
"NOR": {}, "OMN": {}, "PAK": {}, "PLW": {}, "PSE": {},
"PAN": {}, "PNG": {}, "PRY": {}, "PER": {}, "PHL": {},
"PCN": {}, "POL": {}, "PRT": {}, "PRI": {}, "QAT": {},
"ROU": {}, "RUS": {}, "RWA": {}, "REU": {}, "BLM": {},
"SHN": {}, "KNA": {}, "LCA": {}, "MAF": {}, "SPM": {},
"VCT": {}, "WSM": {}, "SMR": {}, "STP": {}, "SAU": {},
"SEN": {}, "SRB": {}, "SYC": {}, "SLE": {}, "SGP": {},
"SXM": {}, "SVK": {}, "SVN": {}, "SLB": {}, "SOM": {},
"ZAF": {}, "SGS": {}, "SSD": {}, "ESP": {}, "LKA": {},
"SDN": {}, "SUR": {}, "SJM": {}, "SWE": {}, "CHE": {},
"SYR": {}, "TWN": {}, "TJK": {}, "TZA": {}, "THA": {},
"TLS": {}, "TGO": {}, "TKL": {}, "TON": {}, "TTO": {},
"TUN": {}, "TUR": {}, "TKM": {}, "TCA": {}, "TUV": {},
"UGA": {}, "UKR": {}, "ARE": {}, "GBR": {}, "UMI": {},
"USA": {}, "URY": {}, "UZB": {}, "VUT": {}, "VEN": {},
"VNM": {}, "VGB": {}, "VIR": {}, "WLF": {}, "ESH": {},
"YEM": {}, "ZMB": {}, "ZWE": {}, "ALA": {}, "UNK": {},
}
var iso3166_1_alpha3_eu = map[string]struct{}{
"AUT": {}, "BEL": {}, "BGR": {}, "HRV": {}, "CYP": {},
"CZE": {}, "DNK": {}, "EST": {}, "FIN": {}, "FRA": {},
"DEU": {}, "GRC": {}, "HUN": {}, "IRL": {}, "ITA": {},
"LVA": {}, "LTU": {}, "LUX": {}, "MLT": {}, "NLD": {},
"POL": {}, "PRT": {}, "ROU": {}, "SVK": {}, "SVN": {},
"ESP": {}, "SWE": {},
}
var iso3166_1_alpha_numeric = map[int]struct{}{
// see: https://www.iso.org/iso-3166-country-codes.html
4: {}, 8: {}, 12: {}, 16: {}, 20: {},
24: {}, 660: {}, 10: {}, 28: {}, 32: {},
51: {}, 533: {}, 36: {}, 40: {}, 31: {},
44: {}, 48: {}, 50: {}, 52: {}, 112: {},
56: {}, 84: {}, 204: {}, 60: {}, 64: {},
68: {}, 535: {}, 70: {}, 72: {}, 74: {},
76: {}, 86: {}, 96: {}, 100: {}, 854: {},
108: {}, 132: {}, 116: {}, 120: {}, 124: {},
136: {}, 140: {}, 148: {}, 152: {}, 156: {},
162: {}, 166: {}, 170: {}, 174: {}, 180: {},
178: {}, 184: {}, 188: {}, 191: {}, 192: {},
531: {}, 196: {}, 203: {}, 384: {}, 208: {},
262: {}, 212: {}, 214: {}, 218: {}, 818: {},
222: {}, 226: {}, 232: {}, 233: {}, 748: {},
231: {}, 238: {}, 234: {}, 242: {}, 246: {},
250: {}, 254: {}, 258: {}, 260: {}, 266: {},
270: {}, 268: {}, 276: {}, 288: {}, 292: {},
300: {}, 304: {}, 308: {}, 312: {}, 316: {},
320: {}, 831: {}, 324: {}, 624: {}, 328: {},
332: {}, 334: {}, 336: {}, 340: {}, 344: {},
348: {}, 352: {}, 356: {}, 360: {}, 364: {},
368: {}, 372: {}, 833: {}, 376: {}, 380: {},
388: {}, 392: {}, 832: {}, 400: {}, 398: {},
404: {}, 296: {}, 408: {}, 410: {}, 414: {},
417: {}, 418: {}, 428: {}, 422: {}, 426: {},
430: {}, 434: {}, 438: {}, 440: {}, 442: {},
446: {}, 450: {}, 454: {}, 458: {}, 462: {},
466: {}, 470: {}, 584: {}, 474: {}, 478: {},
480: {}, 175: {}, 484: {}, 583: {}, 498: {},
492: {}, 496: {}, 499: {}, 500: {}, 504: {},
508: {}, 104: {}, 516: {}, 520: {}, 524: {},
528: {}, 540: {}, 554: {}, 558: {}, 562: {},
566: {}, 570: {}, 574: {}, 807: {}, 580: {},
578: {}, 512: {}, 586: {}, 585: {}, 275: {},
591: {}, 598: {}, 600: {}, 604: {}, 608: {},
612: {}, 616: {}, 620: {}, 630: {}, 634: {},
642: {}, 643: {}, 646: {}, 638: {}, 652: {},
654: {}, 659: {}, 662: {}, 663: {}, 666: {},
670: {}, 882: {}, 674: {}, 678: {}, 682: {},
686: {}, 688: {}, 690: {}, 694: {}, 702: {},
534: {}, 703: {}, 705: {}, 90: {}, 706: {},
710: {}, 239: {}, 728: {}, 724: {}, 144: {},
729: {}, 740: {}, 744: {}, 752: {}, 756: {},
760: {}, 158: {}, 762: {}, 834: {}, 764: {},
626: {}, 768: {}, 772: {}, 776: {}, 780: {},
788: {}, 792: {}, 795: {}, 796: {}, 798: {},
800: {}, 804: {}, 784: {}, 826: {}, 581: {},
840: {}, 858: {}, 860: {}, 548: {}, 862: {},
704: {}, 92: {}, 850: {}, 876: {}, 732: {},
887: {}, 894: {}, 716: {}, 248: {}, 153: {},
}
var iso3166_1_alpha_numeric_eu = map[int]struct{}{
40: {}, 56: {}, 100: {}, 191: {}, 196: {},
200: {}, 208: {}, 233: {}, 246: {}, 250: {},
276: {}, 300: {}, 348: {}, 372: {}, 380: {},
428: {}, 440: {}, 442: {}, 470: {}, 528: {},
616: {}, 620: {}, 642: {}, 703: {}, 705: {},
724: {}, 752: {},
}
var iso3166_2 = map[string]struct{}{
"AD-02": {}, "AD-03": {}, "AD-04": {}, "AD-05": {}, "AD-06": {},
"AD-07": {}, "AD-08": {}, "AE-AJ": {}, "AE-AZ": {}, "AE-DU": {},
"AE-FU": {}, "AE-RK": {}, "AE-SH": {}, "AE-UQ": {}, "AF-BAL": {},
"AF-BAM": {}, "AF-BDG": {}, "AF-BDS": {}, "AF-BGL": {}, "AF-DAY": {},
"AF-FRA": {}, "AF-FYB": {}, "AF-GHA": {}, "AF-GHO": {}, "AF-HEL": {},
"AF-HER": {}, "AF-JOW": {}, "AF-KAB": {}, "AF-KAN": {}, "AF-KAP": {},
"AF-KDZ": {}, "AF-KHO": {}, "AF-KNR": {}, "AF-LAG": {}, "AF-LOG": {},
"AF-NAN": {}, "AF-NIM": {}, "AF-NUR": {}, "AF-PAN": {}, "AF-PAR": {},
"AF-PIA": {}, "AF-PKA": {}, "AF-SAM": {}, "AF-SAR": {}, "AF-TAK": {},
"AF-URU": {}, "AF-WAR": {}, "AF-ZAB": {}, "AG-03": {}, "AG-04": {},
"AG-05": {}, "AG-06": {}, "AG-07": {}, "AG-08": {}, "AG-10": {},
"AG-11": {}, "AL-01": {}, "AL-02": {}, "AL-03": {}, "AL-04": {},
"AL-05": {}, "AL-06": {}, "AL-07": {}, "AL-08": {}, "AL-09": {},
"AL-10": {}, "AL-11": {}, "AL-12": {}, "AL-BR": {}, "AL-BU": {},
"AL-DI": {}, "AL-DL": {}, "AL-DR": {}, "AL-DV": {}, "AL-EL": {},
"AL-ER": {}, "AL-FR": {}, "AL-GJ": {}, "AL-GR": {}, "AL-HA": {},
"AL-KA": {}, "AL-KB": {}, "AL-KC": {}, "AL-KO": {}, "AL-KR": {},
"AL-KU": {}, "AL-LB": {}, "AL-LE": {}, "AL-LU": {}, "AL-MK": {},
"AL-MM": {}, "AL-MR": {}, "AL-MT": {}, "AL-PG": {}, "AL-PQ": {},
"AL-PR": {}, "AL-PU": {}, "AL-SH": {}, "AL-SK": {}, "AL-SR": {},
"AL-TE": {}, "AL-TP": {}, "AL-TR": {}, "AL-VL": {}, "AM-AG": {},
"AM-AR": {}, "AM-AV": {}, "AM-ER": {}, "AM-GR": {}, "AM-KT": {},
"AM-LO": {}, "AM-SH": {}, "AM-SU": {}, "AM-TV": {}, "AM-VD": {},
"AO-BGO": {}, "AO-BGU": {}, "AO-BIE": {}, "AO-CAB": {}, "AO-CCU": {},
"AO-CNN": {}, "AO-CNO": {}, "AO-CUS": {}, "AO-HUA": {}, "AO-HUI": {},
"AO-LNO": {}, "AO-LSU": {}, "AO-LUA": {}, "AO-MAL": {}, "AO-MOX": {},
"AO-NAM": {}, "AO-UIG": {}, "AO-ZAI": {}, "AR-A": {}, "AR-B": {},
"AR-C": {}, "AR-D": {}, "AR-E": {}, "AR-F": {}, "AR-G": {}, "AR-H": {},
"AR-J": {}, "AR-K": {}, "AR-L": {}, "AR-M": {}, "AR-N": {},
"AR-P": {}, "AR-Q": {}, "AR-R": {}, "AR-S": {}, "AR-T": {},
"AR-U": {}, "AR-V": {}, "AR-W": {}, "AR-X": {}, "AR-Y": {},
"AR-Z": {}, "AT-1": {}, "AT-2": {}, "AT-3": {}, "AT-4": {},
"AT-5": {}, "AT-6": {}, "AT-7": {}, "AT-8": {}, "AT-9": {},
"AU-ACT": {}, "AU-NSW": {}, "AU-NT": {}, "AU-QLD": {}, "AU-SA": {},
"AU-TAS": {}, "AU-VIC": {}, "AU-WA": {}, "AZ-ABS": {}, "AZ-AGA": {},
"AZ-AGC": {}, "AZ-AGM": {}, "AZ-AGS": {}, "AZ-AGU": {}, "AZ-AST": {},
"AZ-BA": {}, "AZ-BAB": {}, "AZ-BAL": {}, "AZ-BAR": {}, "AZ-BEY": {},
"AZ-BIL": {}, "AZ-CAB": {}, "AZ-CAL": {}, "AZ-CUL": {}, "AZ-DAS": {},
"AZ-FUZ": {}, "AZ-GA": {}, "AZ-GAD": {}, "AZ-GOR": {}, "AZ-GOY": {},
"AZ-GYG": {}, "AZ-HAC": {}, "AZ-IMI": {}, "AZ-ISM": {}, "AZ-KAL": {},
"AZ-KAN": {}, "AZ-KUR": {}, "AZ-LA": {}, "AZ-LAC": {}, "AZ-LAN": {},
"AZ-LER": {}, "AZ-MAS": {}, "AZ-MI": {}, "AZ-NA": {}, "AZ-NEF": {},
"AZ-NV": {}, "AZ-NX": {}, "AZ-OGU": {}, "AZ-ORD": {}, "AZ-QAB": {},
"AZ-QAX": {}, "AZ-QAZ": {}, "AZ-QBA": {}, "AZ-QBI": {}, "AZ-QOB": {},
"AZ-QUS": {}, "AZ-SA": {}, "AZ-SAB": {}, "AZ-SAD": {}, "AZ-SAH": {},
"AZ-SAK": {}, "AZ-SAL": {}, "AZ-SAR": {}, "AZ-SAT": {}, "AZ-SBN": {},
"AZ-SIY": {}, "AZ-SKR": {}, "AZ-SM": {}, "AZ-SMI": {}, "AZ-SMX": {},
"AZ-SR": {}, "AZ-SUS": {}, "AZ-TAR": {}, "AZ-TOV": {}, "AZ-UCA": {},
"AZ-XA": {}, "AZ-XAC": {}, "AZ-XCI": {}, "AZ-XIZ": {}, "AZ-XVD": {},
"AZ-YAR": {}, "AZ-YE": {}, "AZ-YEV": {}, "AZ-ZAN": {}, "AZ-ZAQ": {},
"AZ-ZAR": {}, "BA-01": {}, "BA-02": {}, "BA-03": {}, "BA-04": {},
gitextract_ki70tqza/ ├── .github/ │ ├── CODEOWNERS │ ├── CONTRIBUTING.md │ ├── ISSUE_TEMPLATE/ │ │ └── bug_report.yml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── dependabot.yml │ └── workflows/ │ └── workflow.yml ├── .gitignore ├── .golangci.yaml ├── LICENSE ├── MAINTAINERS.md ├── Makefile ├── README.md ├── _examples/ │ ├── custom/ │ │ └── main.go │ ├── custom-validation/ │ │ └── main.go │ ├── dive/ │ │ └── main.go │ ├── gin-upgrading-overriding/ │ │ ├── main.go │ │ └── v8_to_v9.go │ ├── http-transalations/ │ │ └── main.go │ ├── map-validation/ │ │ └── main.go │ ├── simple/ │ │ └── main.go │ ├── struct-level/ │ │ └── main.go │ ├── struct-map-rules-validation/ │ │ └── main.go │ ├── translations/ │ │ └── main.go │ ├── validate_fn/ │ │ ├── enum_enumer.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ └── valuer/ │ └── main.go ├── baked_in.go ├── benchmarks_test.go ├── cache.go ├── country_codes.go ├── currency_codes.go ├── doc.go ├── errors.go ├── field_level.go ├── go.mod ├── go.sum ├── non-standard/ │ └── validators/ │ ├── notblank.go │ └── notblank_test.go ├── options.go ├── postcode_regexes.go ├── regexes.go ├── struct_level.go ├── testdata/ │ └── a.go ├── translations/ │ ├── ar/ │ │ ├── ar.go │ │ └── ar_test.go │ ├── de/ │ │ ├── de.go │ │ └── de_test.go │ ├── en/ │ │ ├── en.go │ │ └── en_test.go │ ├── es/ │ │ ├── es.go │ │ └── es_test.go │ ├── fa/ │ │ ├── fa.go │ │ └── fa_test.go │ ├── fr/ │ │ ├── fr.go │ │ └── fr_test.go │ ├── id/ │ │ ├── id.go │ │ └── id_test.go │ ├── it/ │ │ ├── it.go │ │ └── it_test.go │ ├── ja/ │ │ ├── ja.go │ │ └── ja_test.go │ ├── ko/ │ │ ├── ko.go │ │ └── ko_test.go │ ├── lv/ │ │ ├── lv.go │ │ └── lv_test.go │ ├── nl/ │ │ ├── nl.go │ │ └── nl_test.go │ ├── pl/ │ │ ├── pl.go │ │ └── pl_test.go │ ├── pt/ │ │ ├── pt.go │ │ └── pt_test.go │ ├── pt_BR/ │ │ ├── pt_BR.go │ │ └── pt_BR_test.go │ ├── ru/ │ │ ├── ru.go │ │ └── ru_test.go │ ├── th/ │ │ ├── th.go │ │ └── th_test.go │ ├── tr/ │ │ ├── tr.go │ │ └── tr_test.go │ ├── uk/ │ │ ├── uk.go │ │ └── uk_test.go │ ├── vi/ │ │ ├── vi.go │ │ └── vi_test.go │ ├── zh/ │ │ ├── zh.go │ │ └── zh_test.go │ └── zh_tw/ │ ├── zh_tw.go │ └── zh_tw_test.go ├── translations.go ├── util.go ├── validator.go ├── validator_instance.go └── validator_test.go
SYMBOL INDEX (995 symbols across 74 files)
FILE: _examples/custom-validation/main.go
type MyStruct (line 10) | type MyStruct struct
function main (line 17) | func main() {
function ValidateMyVal (line 37) | func ValidateMyVal(fl validator.FieldLevel) bool {
FILE: _examples/custom/main.go
type DbBackedUser (line 13) | type DbBackedUser struct
function main (line 21) | func main() {
function ValidateValuer (line 39) | func ValidateValuer(field reflect.Value) interface{} {
FILE: _examples/dive/main.go
type Test (line 10) | type Test struct
function main (line 18) | func main() {
function val (line 35) | func val(test Test) {
FILE: _examples/gin-upgrading-overriding/main.go
function main (line 5) | func main() {
FILE: _examples/gin-upgrading-overriding/v8_to_v9.go
type defaultValidator (line 11) | type defaultValidator struct
method ValidateStruct (line 18) | func (v *defaultValidator) ValidateStruct(obj interface{}) error {
method Engine (line 32) | func (v *defaultValidator) Engine() interface{} {
method lazyinit (line 37) | func (v *defaultValidator) lazyinit() {
function kindOfData (line 46) | func kindOfData(data interface{}) reflect.Kind {
FILE: _examples/http-transalations/main.go
function main (line 26) | func main() {
FILE: _examples/map-validation/main.go
function main (line 10) | func main() {
function validateMap (line 17) | func validateMap() {
function validateNestedMap (line 40) | func validateNestedMap() {
FILE: _examples/simple/main.go
type User (line 11) | type User struct
type Address (line 22) | type Address struct
function main (line 32) | func main() {
function validateStruct (line 40) | func validateStruct() {
function validateVariable (line 95) | func validateVariable() {
FILE: _examples/struct-level/main.go
type validationError (line 13) | type validationError struct
type Gender (line 27) | type Gender
method String (line 35) | func (gender Gender) String() string {
constant Male (line 30) | Male Gender = iota + 1
constant Female (line 31) | Female
constant Intersex (line 32) | Intersex
type User (line 44) | type User struct
type Address (line 55) | type Address struct
function main (line 65) | func main() {
function UserStructLevelValidation (line 167) | func UserStructLevelValidation(sl validator.StructLevel) {
FILE: _examples/struct-map-rules-validation/main.go
type Data (line 8) | type Data struct
type Details (line 14) | type Details struct
type FamilyMembers (line 19) | type FamilyMembers struct
type Data2 (line 24) | type Data2 struct
function main (line 31) | func main() {
function validateStruct (line 43) | func validateStruct() {
function validateStructNested (line 61) | func validateStructNested() {
FILE: _examples/translations/main.go
type User (line 13) | type User struct
type Address (line 23) | type Address struct
function main (line 36) | func main() {
function translateAll (line 55) | func translateAll(trans ut.Translator) {
function translateIndividual (line 83) | func translateIndividual(trans ut.Translator) {
function translateOverride (line 103) | func translateOverride(trans ut.Translator) {
FILE: _examples/validate_fn/enum_enumer.go
constant _EnumName (line 10) | _EnumName = "ZeroOneTwoThree"
constant _EnumLowerName (line 14) | _EnumLowerName = "zeroonetwothree"
method String (line 16) | func (i Enum) String() string {
function _EnumNoOp (line 25) | func _EnumNoOp() {
function EnumString (line 55) | func EnumString(s string) (Enum, error) {
function EnumValues (line 67) | func EnumValues() []Enum {
function EnumStrings (line 72) | func EnumStrings() []string {
method IsAEnum (line 79) | func (i Enum) IsAEnum() bool {
FILE: _examples/validate_fn/main.go
type Enum (line 11) | type Enum
method Validate (line 20) | func (e *Enum) Validate() error {
constant Zero (line 14) | Zero Enum = iota
constant One (line 15) | One
constant Two (line 16) | Two
constant Three (line 17) | Three
type Struct (line 28) | type Struct struct
function main (line 33) | func main() {
FILE: _examples/valuer/main.go
type Nullable (line 11) | type Nullable struct
method ValidatorValue (line 16) | func (n Nullable[T]) ValidatorValue() any {
type Config (line 20) | type Config struct
type Record (line 24) | type Record struct
function main (line 31) | func main() {
FILE: baked_in.go
type Func (line 36) | type Func
type FuncCtx (line 40) | type FuncCtx
function wrapFunc (line 43) | func wrapFunc(fn Func) FuncCtx {
function parseOneOfParam2 (line 266) | func parseOneOfParam2(s string) []string {
function isURLEncoded (line 282) | func isURLEncoded(fl FieldLevel) bool {
function isHTMLEncoded (line 286) | func isHTMLEncoded(fl FieldLevel) bool {
function isHTML (line 290) | func isHTML(fl FieldLevel) bool {
function isOneOf (line 294) | func isOneOf(fl FieldLevel) bool {
function isOneOfCI (line 319) | func isOneOfCI(fl FieldLevel) bool {
function isUnique (line 336) | func isUnique(fl FieldLevel) bool {
function isMAC (line 458) | func isMAC(fl FieldLevel) bool {
function isCIDRv4 (line 465) | func isCIDRv4(fl FieldLevel) bool {
function isCIDRv6 (line 472) | func isCIDRv6(fl FieldLevel) bool {
function isCIDR (line 479) | func isCIDR(fl FieldLevel) bool {
function isIPv4 (line 486) | func isIPv4(fl FieldLevel) bool {
function isIPv6 (line 493) | func isIPv6(fl FieldLevel) bool {
function isIP (line 500) | func isIP(fl FieldLevel) bool {
function isSSN (line 507) | func isSSN(fl FieldLevel) bool {
function isLongitude (line 518) | func isLongitude(fl FieldLevel) bool {
function isLatitude (line 541) | func isLatitude(fl FieldLevel) bool {
function isDataURI (line 564) | func isDataURI(fl FieldLevel) bool {
function hasMultiByteCharacter (line 579) | func hasMultiByteCharacter(fl FieldLevel) bool {
function isPrintableASCII (line 590) | func isPrintableASCII(fl FieldLevel) bool {
function isASCII (line 599) | func isASCII(fl FieldLevel) bool {
function isUUID5 (line 608) | func isUUID5(fl FieldLevel) bool {
function isUUID4 (line 613) | func isUUID4(fl FieldLevel) bool {
function isUUID3 (line 618) | func isUUID3(fl FieldLevel) bool {
function isUUID (line 623) | func isUUID(fl FieldLevel) bool {
function isUUID5RFC4122 (line 628) | func isUUID5RFC4122(fl FieldLevel) bool {
function isUUID4RFC4122 (line 633) | func isUUID4RFC4122(fl FieldLevel) bool {
function isUUID3RFC4122 (line 638) | func isUUID3RFC4122(fl FieldLevel) bool {
function isUUIDRFC4122 (line 643) | func isUUIDRFC4122(fl FieldLevel) bool {
function isULID (line 648) | func isULID(fl FieldLevel) bool {
function isMD4 (line 653) | func isMD4(fl FieldLevel) bool {
function isMD5 (line 658) | func isMD5(fl FieldLevel) bool {
function isSHA256 (line 663) | func isSHA256(fl FieldLevel) bool {
function isSHA384 (line 668) | func isSHA384(fl FieldLevel) bool {
function isSHA512 (line 673) | func isSHA512(fl FieldLevel) bool {
function isRIPEMD128 (line 678) | func isRIPEMD128(fl FieldLevel) bool {
function isRIPEMD160 (line 683) | func isRIPEMD160(fl FieldLevel) bool {
function isTIGER128 (line 688) | func isTIGER128(fl FieldLevel) bool {
function isTIGER160 (line 693) | func isTIGER160(fl FieldLevel) bool {
function isTIGER192 (line 698) | func isTIGER192(fl FieldLevel) bool {
function isISBN (line 703) | func isISBN(fl FieldLevel) bool {
function isISBN13 (line 708) | func isISBN13(fl FieldLevel) bool {
function isISBN10 (line 728) | func isISBN10(fl FieldLevel) bool {
function isISSN (line 752) | func isISSN(fl FieldLevel) bool {
function isEthereumAddress (line 778) | func isEthereumAddress(fl FieldLevel) bool {
function isEthereumAddressChecksum (line 785) | func isEthereumAddressChecksum(fl FieldLevel) bool {
function isBitcoinAddress (line 811) | func isBitcoinAddress(fl FieldLevel) bool {
function isBitcoinBech32Address (line 848) | func isBitcoinBech32Address(fl FieldLevel) bool {
function excludesRune (line 928) | func excludesRune(fl FieldLevel) bool {
function excludesAll (line 933) | func excludesAll(fl FieldLevel) bool {
function excludes (line 938) | func excludes(fl FieldLevel) bool {
function containsRune (line 943) | func containsRune(fl FieldLevel) bool {
function containsAny (line 950) | func containsAny(fl FieldLevel) bool {
function contains (line 955) | func contains(fl FieldLevel) bool {
function startsWith (line 960) | func startsWith(fl FieldLevel) bool {
function endsWith (line 965) | func endsWith(fl FieldLevel) bool {
function startsNotWith (line 970) | func startsNotWith(fl FieldLevel) bool {
function endsNotWith (line 975) | func endsNotWith(fl FieldLevel) bool {
function fieldContains (line 980) | func fieldContains(fl FieldLevel) bool {
function fieldExcludes (line 993) | func fieldExcludes(fl FieldLevel) bool {
function isNeField (line 1005) | func isNeField(fl FieldLevel) bool {
function isNe (line 1053) | func isNe(fl FieldLevel) bool {
function isNeIgnoreCase (line 1059) | func isNeIgnoreCase(fl FieldLevel) bool {
function isLteCrossStructField (line 1064) | func isLteCrossStructField(fl FieldLevel) bool {
function isLtCrossStructField (line 1109) | func isLtCrossStructField(fl FieldLevel) bool {
function isGteCrossStructField (line 1153) | func isGteCrossStructField(fl FieldLevel) bool {
function isGtCrossStructField (line 1197) | func isGtCrossStructField(fl FieldLevel) bool {
function isNeCrossStructField (line 1241) | func isNeCrossStructField(fl FieldLevel) bool {
function isEqCrossStructField (line 1288) | func isEqCrossStructField(fl FieldLevel) bool {
function isEqField (line 1335) | func isEqField(fl FieldLevel) bool {
function isEq (line 1382) | func isEq(fl FieldLevel) bool {
function isEqIgnoreCase (line 1427) | func isEqIgnoreCase(fl FieldLevel) bool {
function isPostcodeByIso3166Alpha2 (line 1441) | func isPostcodeByIso3166Alpha2(fl FieldLevel) bool {
function isPostcodeByIso3166Alpha2Field (line 1456) | func isPostcodeByIso3166Alpha2Field(fl FieldLevel) bool {
function isBase32 (line 1483) | func isBase32(fl FieldLevel) bool {
function isBase64 (line 1488) | func isBase64(fl FieldLevel) bool {
function isBase64URL (line 1493) | func isBase64URL(fl FieldLevel) bool {
function isBase64RawURL (line 1498) | func isBase64RawURL(fl FieldLevel) bool {
function isURI (line 1503) | func isURI(fl FieldLevel) bool {
function isURL (line 1530) | func isURL(fl FieldLevel) bool {
function isHttpURL (line 1559) | func isHttpURL(fl FieldLevel) bool {
function isHttpsURL (line 1582) | func isHttpsURL(fl FieldLevel) bool {
function isUrnRFC2141 (line 1605) | func isUrnRFC2141(fl FieldLevel) bool {
function isFile (line 1622) | func isFile(fl FieldLevel) bool {
function isImage (line 1639) | func isImage(fl FieldLevel) bool {
function isFilePath (line 1702) | func isFilePath(fl FieldLevel) bool {
function isE164 (line 1756) | func isE164(fl FieldLevel) bool {
function isEmail (line 1761) | func isEmail(fl FieldLevel) bool {
function isHSLA (line 1770) | func isHSLA(fl FieldLevel) bool {
function isCMYK (line 1775) | func isCMYK(fl FieldLevel) bool {
function isHSL (line 1780) | func isHSL(fl FieldLevel) bool {
function isRGBA (line 1785) | func isRGBA(fl FieldLevel) bool {
function isRGB (line 1790) | func isRGB(fl FieldLevel) bool {
function isHEXColor (line 1795) | func isHEXColor(fl FieldLevel) bool {
function isHexadecimal (line 1800) | func isHexadecimal(fl FieldLevel) bool {
function isNumber (line 1805) | func isNumber(fl FieldLevel) bool {
function isNumeric (line 1815) | func isNumeric(fl FieldLevel) bool {
function isAlphanum (line 1825) | func isAlphanum(fl FieldLevel) bool {
function isAlpha (line 1830) | func isAlpha(fl FieldLevel) bool {
function isAlphanumUnicode (line 1835) | func isAlphanumUnicode(fl FieldLevel) bool {
function isAlphaSpace (line 1840) | func isAlphaSpace(fl FieldLevel) bool {
function isAlphaNumericSpace (line 1845) | func isAlphaNumericSpace(fl FieldLevel) bool {
function isAlphaUnicode (line 1850) | func isAlphaUnicode(fl FieldLevel) bool {
function isBoolean (line 1855) | func isBoolean(fl FieldLevel) bool {
function isDefault (line 1866) | func isDefault(fl FieldLevel) bool {
function hasValue (line 1871) | func hasValue(fl FieldLevel) bool {
function hasNotZeroValue (line 1885) | func hasNotZeroValue(fl FieldLevel) bool {
function requireCheckFieldKind (line 1902) | func requireCheckFieldKind(fl FieldLevel, param string, defaultNotFoundV...
function requireCheckFieldValue (line 1926) | func requireCheckFieldValue(
function requiredIf (line 1973) | func requiredIf(fl FieldLevel) bool {
function excludedIf (line 1997) | func excludedIf(fl FieldLevel) bool {
function requiredUnless (line 2013) | func requiredUnless(fl FieldLevel) bool {
function skipUnless (line 2029) | func skipUnless(fl FieldLevel) bool {
function excludedUnless (line 2044) | func excludedUnless(fl FieldLevel) bool {
function excludedWith (line 2060) | func excludedWith(fl FieldLevel) bool {
function requiredWith (line 2072) | func requiredWith(fl FieldLevel) bool {
function excludedWithAll (line 2084) | func excludedWithAll(fl FieldLevel) bool {
function requiredWithAll (line 2096) | func requiredWithAll(fl FieldLevel) bool {
function excludedWithout (line 2108) | func excludedWithout(fl FieldLevel) bool {
function requiredWithout (line 2117) | func requiredWithout(fl FieldLevel) bool {
function excludedWithoutAll (line 2129) | func excludedWithoutAll(fl FieldLevel) bool {
function requiredWithoutAll (line 2141) | func requiredWithoutAll(fl FieldLevel) bool {
function isGteField (line 2152) | func isGteField(fl FieldLevel) bool {
function isGtField (line 2196) | func isGtField(fl FieldLevel) bool {
function isGte (line 2240) | func isGte(fl FieldLevel) bool {
function isGt (line 2289) | func isGt(fl FieldLevel) bool {
function hasLengthOf (line 2335) | func hasLengthOf(fl FieldLevel) bool {
function hasMinOf (line 2375) | func hasMinOf(fl FieldLevel) bool {
function isLteField (line 2380) | func isLteField(fl FieldLevel) bool {
function isLtField (line 2424) | func isLtField(fl FieldLevel) bool {
function isLte (line 2468) | func isLte(fl FieldLevel) bool {
function isLt (line 2517) | func isLt(fl FieldLevel) bool {
function hasMaxOf (line 2563) | func hasMaxOf(fl FieldLevel) bool {
function isTCP4AddrResolvable (line 2568) | func isTCP4AddrResolvable(fl FieldLevel) bool {
function isTCP6AddrResolvable (line 2578) | func isTCP6AddrResolvable(fl FieldLevel) bool {
function isTCPAddrResolvable (line 2589) | func isTCPAddrResolvable(fl FieldLevel) bool {
function isUDP4AddrResolvable (line 2600) | func isUDP4AddrResolvable(fl FieldLevel) bool {
function isUDP6AddrResolvable (line 2611) | func isUDP6AddrResolvable(fl FieldLevel) bool {
function isUDPAddrResolvable (line 2622) | func isUDPAddrResolvable(fl FieldLevel) bool {
function isIP4AddrResolvable (line 2633) | func isIP4AddrResolvable(fl FieldLevel) bool {
function isIP6AddrResolvable (line 2644) | func isIP6AddrResolvable(fl FieldLevel) bool {
function isIPAddrResolvable (line 2655) | func isIPAddrResolvable(fl FieldLevel) bool {
function isUnixAddrResolvable (line 2666) | func isUnixAddrResolvable(fl FieldLevel) bool {
function isUnixDomainSocketExists (line 2675) | func isUnixDomainSocketExists(fl FieldLevel) bool {
function isAbstractSocketExists (line 2702) | func isAbstractSocketExists(sockpath string) bool {
function isIP4Addr (line 2736) | func isIP4Addr(fl FieldLevel) bool {
function isIP6Addr (line 2748) | func isIP6Addr(fl FieldLevel) bool {
function isHostnameRFC952 (line 2762) | func isHostnameRFC952(fl FieldLevel) bool {
function isHostnameRFC1123 (line 2766) | func isHostnameRFC1123(fl FieldLevel) bool {
function isFQDN (line 2770) | func isFQDN(fl FieldLevel) bool {
function isDir (line 2781) | func isDir(fl FieldLevel) bool {
function isDirPath (line 2797) | func isDirPath(fl FieldLevel) bool {
function isJSON (line 2854) | func isJSON(fl FieldLevel) bool {
function isJWT (line 2874) | func isJWT(fl FieldLevel) bool {
function isHostnamePort (line 2879) | func isHostnamePort(fl FieldLevel) bool {
function isPort (line 2900) | func isPort(fl FieldLevel) bool {
function isLowercase (line 2907) | func isLowercase(fl FieldLevel) bool {
function isUppercase (line 2921) | func isUppercase(fl FieldLevel) bool {
function isDatetime (line 2935) | func isDatetime(fl FieldLevel) bool {
function isTimeZone (line 2949) | func isTimeZone(fl FieldLevel) bool {
function isIso3166Alpha2 (line 2971) | func isIso3166Alpha2(fl FieldLevel) bool {
function isIso3166Alpha2EU (line 2977) | func isIso3166Alpha2EU(fl FieldLevel) bool {
function isIso3166Alpha3 (line 2983) | func isIso3166Alpha3(fl FieldLevel) bool {
function isIso3166Alpha3EU (line 2989) | func isIso3166Alpha3EU(fl FieldLevel) bool {
function isIso3166AlphaNumeric (line 2995) | func isIso3166AlphaNumeric(fl FieldLevel) bool {
function isIso3166AlphaNumericEU (line 3019) | func isIso3166AlphaNumericEU(fl FieldLevel) bool {
function isIso31662 (line 3043) | func isIso31662(fl FieldLevel) bool {
function isIso4217 (line 3049) | func isIso4217(fl FieldLevel) bool {
function isIso4217Numeric (line 3055) | func isIso4217Numeric(fl FieldLevel) bool {
function isBCP47LanguageTag (line 3073) | func isBCP47LanguageTag(fl FieldLevel) bool {
function isIsoBic2014Format (line 3085) | func isIsoBic2014Format(fl FieldLevel) bool {
function isIsoBic2022Format (line 3092) | func isIsoBic2022Format(fl FieldLevel) bool {
function isSemverFormat (line 3099) | func isSemverFormat(fl FieldLevel) bool {
function isCveFormat (line 3106) | func isCveFormat(fl FieldLevel) bool {
function isDnsRFC1035LabelFormat (line 3115) | func isDnsRFC1035LabelFormat(fl FieldLevel) bool {
function digitsHaveLuhnChecksum (line 3127) | func digitsHaveLuhnChecksum(digits []string) bool {
function isMongoDBObjectId (line 3150) | func isMongoDBObjectId(fl FieldLevel) bool {
function isMongoDBConnectionString (line 3156) | func isMongoDBConnectionString(fl FieldLevel) bool {
function isSpiceDB (line 3162) | func isSpiceDB(fl FieldLevel) bool {
function isCreditCard (line 3179) | func isCreditCard(fl FieldLevel) bool {
function hasLuhnChecksum (line 3200) | func hasLuhnChecksum(fl FieldLevel) bool {
function isCron (line 3222) | func isCron(fl FieldLevel) bool {
function isEIN (line 3228) | func isEIN(fl FieldLevel) bool {
function isValidateFn (line 3238) | func isValidateFn(fl FieldLevel) bool {
function tryCallValidateFn (line 3258) | func tryCallValidateFn(field reflect.Value, validateFn string) (bool, er...
FILE: benchmarks_test.go
function BenchmarkFieldSuccess (line 11) | func BenchmarkFieldSuccess(b *testing.B) {
function BenchmarkFieldSuccessParallel (line 21) | func BenchmarkFieldSuccessParallel(b *testing.B) {
function BenchmarkFieldFailure (line 33) | func BenchmarkFieldFailure(b *testing.B) {
function BenchmarkFieldFailureParallel (line 43) | func BenchmarkFieldFailureParallel(b *testing.B) {
function BenchmarkFieldArrayDiveSuccess (line 55) | func BenchmarkFieldArrayDiveSuccess(b *testing.B) {
function BenchmarkFieldArrayDiveSuccessParallel (line 66) | func BenchmarkFieldArrayDiveSuccessParallel(b *testing.B) {
function BenchmarkFieldArrayDiveFailure (line 78) | func BenchmarkFieldArrayDiveFailure(b *testing.B) {
function BenchmarkFieldArrayDiveFailureParallel (line 88) | func BenchmarkFieldArrayDiveFailureParallel(b *testing.B) {
function BenchmarkFieldMapDiveSuccess (line 100) | func BenchmarkFieldMapDiveSuccess(b *testing.B) {
function BenchmarkFieldMapDiveSuccessParallel (line 111) | func BenchmarkFieldMapDiveSuccessParallel(b *testing.B) {
function BenchmarkFieldMapDiveFailure (line 123) | func BenchmarkFieldMapDiveFailure(b *testing.B) {
function BenchmarkFieldMapDiveFailureParallel (line 133) | func BenchmarkFieldMapDiveFailureParallel(b *testing.B) {
function BenchmarkFieldMapDiveWithKeysSuccess (line 145) | func BenchmarkFieldMapDiveWithKeysSuccess(b *testing.B) {
function BenchmarkFieldMapDiveWithKeysSuccessParallel (line 156) | func BenchmarkFieldMapDiveWithKeysSuccessParallel(b *testing.B) {
function BenchmarkFieldMapDiveWithKeysFailure (line 168) | func BenchmarkFieldMapDiveWithKeysFailure(b *testing.B) {
function BenchmarkFieldMapDiveWithKeysFailureParallel (line 178) | func BenchmarkFieldMapDiveWithKeysFailureParallel(b *testing.B) {
function BenchmarkFieldCustomTypeSuccess (line 190) | func BenchmarkFieldCustomTypeSuccess(b *testing.B) {
function BenchmarkFieldCustomTypeSuccessParallel (line 203) | func BenchmarkFieldCustomTypeSuccessParallel(b *testing.B) {
function BenchmarkFieldCustomTypeFailure (line 218) | func BenchmarkFieldCustomTypeFailure(b *testing.B) {
function BenchmarkFieldCustomTypeFailureParallel (line 229) | func BenchmarkFieldCustomTypeFailureParallel(b *testing.B) {
function BenchmarkFieldOrTagSuccess (line 242) | func BenchmarkFieldOrTagSuccess(b *testing.B) {
function BenchmarkFieldOrTagSuccessParallel (line 252) | func BenchmarkFieldOrTagSuccessParallel(b *testing.B) {
function BenchmarkFieldOrTagFailure (line 264) | func BenchmarkFieldOrTagFailure(b *testing.B) {
function BenchmarkFieldOrTagFailureParallel (line 274) | func BenchmarkFieldOrTagFailureParallel(b *testing.B) {
function BenchmarkStructLevelValidationSuccess (line 286) | func BenchmarkStructLevelValidationSuccess(b *testing.B) {
function BenchmarkStructLevelValidationSuccessParallel (line 300) | func BenchmarkStructLevelValidationSuccessParallel(b *testing.B) {
function BenchmarkStructLevelValidationFailure (line 316) | func BenchmarkStructLevelValidationFailure(b *testing.B) {
function BenchmarkStructLevelValidationFailureParallel (line 330) | func BenchmarkStructLevelValidationFailureParallel(b *testing.B) {
function BenchmarkStructSimpleCustomTypeSuccess (line 346) | func BenchmarkStructSimpleCustomTypeSuccess(b *testing.B) {
function BenchmarkStructSimpleCustomTypeSuccessParallel (line 367) | func BenchmarkStructSimpleCustomTypeSuccessParallel(b *testing.B) {
function BenchmarkStructSimpleCustomTypeFailure (line 388) | func BenchmarkStructSimpleCustomTypeFailure(b *testing.B) {
function BenchmarkStructSimpleCustomTypeFailureParallel (line 406) | func BenchmarkStructSimpleCustomTypeFailureParallel(b *testing.B) {
function BenchmarkStructFilteredSuccess (line 426) | func BenchmarkStructFilteredSuccess(b *testing.B) {
function BenchmarkStructFilteredSuccessParallel (line 448) | func BenchmarkStructFilteredSuccessParallel(b *testing.B) {
function BenchmarkStructFilteredFailure (line 472) | func BenchmarkStructFilteredFailure(b *testing.B) {
function BenchmarkStructFilteredFailureParallel (line 496) | func BenchmarkStructFilteredFailureParallel(b *testing.B) {
function BenchmarkStructPartialSuccess (line 520) | func BenchmarkStructPartialSuccess(b *testing.B) {
function BenchmarkStructPartialSuccessParallel (line 538) | func BenchmarkStructPartialSuccessParallel(b *testing.B) {
function BenchmarkStructPartialFailure (line 558) | func BenchmarkStructPartialFailure(b *testing.B) {
function BenchmarkStructPartialFailureParallel (line 576) | func BenchmarkStructPartialFailureParallel(b *testing.B) {
function BenchmarkStructExceptSuccess (line 596) | func BenchmarkStructExceptSuccess(b *testing.B) {
function BenchmarkStructExceptSuccessParallel (line 614) | func BenchmarkStructExceptSuccessParallel(b *testing.B) {
function BenchmarkStructExceptFailure (line 634) | func BenchmarkStructExceptFailure(b *testing.B) {
function BenchmarkStructExceptFailureParallel (line 652) | func BenchmarkStructExceptFailureParallel(b *testing.B) {
function BenchmarkStructSimpleCrossFieldSuccess (line 672) | func BenchmarkStructSimpleCrossFieldSuccess(b *testing.B) {
function BenchmarkStructSimpleCrossFieldSuccessParallel (line 693) | func BenchmarkStructSimpleCrossFieldSuccessParallel(b *testing.B) {
function BenchmarkStructSimpleCrossFieldFailure (line 716) | func BenchmarkStructSimpleCrossFieldFailure(b *testing.B) {
function BenchmarkStructSimpleCrossFieldFailureParallel (line 738) | func BenchmarkStructSimpleCrossFieldFailureParallel(b *testing.B) {
function BenchmarkStructSimpleCrossStructCrossFieldSuccess (line 760) | func BenchmarkStructSimpleCrossStructCrossFieldSuccess(b *testing.B) {
function BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel (line 787) | func BenchmarkStructSimpleCrossStructCrossFieldSuccessParallel(b *testin...
function BenchmarkStructSimpleCrossStructCrossFieldFailure (line 816) | func BenchmarkStructSimpleCrossStructCrossFieldFailure(b *testing.B) {
function BenchmarkStructSimpleCrossStructCrossFieldFailureParallel (line 845) | func BenchmarkStructSimpleCrossStructCrossFieldFailureParallel(b *testin...
function BenchmarkStructSimpleSuccess (line 877) | func BenchmarkStructSimpleSuccess(b *testing.B) {
function BenchmarkStructSimpleSuccessParallel (line 892) | func BenchmarkStructSimpleSuccessParallel(b *testing.B) {
function BenchmarkStructSimpleFailure (line 908) | func BenchmarkStructSimpleFailure(b *testing.B) {
function BenchmarkStructSimpleFailureParallel (line 923) | func BenchmarkStructSimpleFailureParallel(b *testing.B) {
function BenchmarkStructComplexSuccess (line 940) | func BenchmarkStructComplexSuccess(b *testing.B) {
function BenchmarkStructComplexSuccessParallel (line 975) | func BenchmarkStructComplexSuccessParallel(b *testing.B) {
function BenchmarkStructComplexFailure (line 1012) | func BenchmarkStructComplexFailure(b *testing.B) {
function BenchmarkStructComplexFailureParallel (line 1044) | func BenchmarkStructComplexFailureParallel(b *testing.B) {
type TestOneof (line 1078) | type TestOneof struct
function BenchmarkOneof (line 1082) | func BenchmarkOneof(b *testing.B) {
function BenchmarkOneofParallel (line 1090) | func BenchmarkOneofParallel(b *testing.B) {
type T (line 1102) | type T struct
method Validate (line 1104) | func (*T) Validate() error { return errors.New("ops") }
function BenchmarkValidateFnSequential (line 1106) | func BenchmarkValidateFnSequential(b *testing.B) {
function BenchmarkValidateFnParallel (line 1121) | func BenchmarkValidateFnParallel(b *testing.B) {
FILE: cache.go
type tagType (line 11) | type tagType
constant typeDefault (line 14) | typeDefault tagType = iota
constant typeOmitEmpty (line 15) | typeOmitEmpty
constant typeIsDefault (line 16) | typeIsDefault
constant typeNoStructLevel (line 17) | typeNoStructLevel
constant typeStructOnly (line 18) | typeStructOnly
constant typeDive (line 19) | typeDive
constant typeOr (line 20) | typeOr
constant typeKeys (line 21) | typeKeys
constant typeEndKeys (line 22) | typeEndKeys
constant typeOmitNil (line 23) | typeOmitNil
constant typeOmitZero (line 24) | typeOmitZero
constant invalidValidation (line 28) | invalidValidation = "Invalid validation tag on field '%s'"
constant undefinedValidation (line 29) | undefinedValidation = "Undefined validation function '%s' on field '%s'"
constant keysTagNotDefined (line 30) | keysTagNotDefined = "'" + endKeysTag + "' tag encountered without a co...
type structCache (line 33) | type structCache struct
method Get (line 38) | func (sc *structCache) Get(key reflect.Type) (c *cStruct, found bool) {
method Set (line 43) | func (sc *structCache) Set(key reflect.Type, value *cStruct) {
type tagCache (line 53) | type tagCache struct
method Get (line 58) | func (tc *tagCache) Get(key string) (c *cTag, found bool) {
method Set (line 63) | func (tc *tagCache) Set(key string, value *cTag) {
type cStruct (line 73) | type cStruct struct
type cField (line 79) | type cField struct
type cTag (line 87) | type cTag struct
method extractStructCache (line 103) | func (v *Validate) extractStructCache(current reflect.Value, sName strin...
method parseFieldTagsRecursive (line 175) | func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string,...
method fetchCacheTag (line 328) | func (v *Validate) fetchCacheTag(tag string) *cTag {
FILE: errors.go
constant fieldErrMsg (line 13) | fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '...
type ValidationErrorsTranslations (line 17) | type ValidationErrorsTranslations
type InvalidValidationError (line 21) | type InvalidValidationError struct
method Error (line 26) | func (e *InvalidValidationError) Error() string {
type ValidationErrors (line 36) | type ValidationErrors
method Error (line 42) | func (ve ValidationErrors) Error() string {
method Translate (line 54) | func (ve ValidationErrors) Translate(ut ut.Translator) ValidationError...
type FieldError (line 76) | type FieldError interface
type fieldError (line 165) | type fieldError struct
method Tag (line 180) | func (fe *fieldError) Tag() string {
method ActualTag (line 186) | func (fe *fieldError) ActualTag() string {
method Namespace (line 192) | func (fe *fieldError) Namespace() string {
method StructNamespace (line 198) | func (fe *fieldError) StructNamespace() string {
method Field (line 204) | func (fe *fieldError) Field() string {
method StructField (line 219) | func (fe *fieldError) StructField() string {
method Value (line 226) | func (fe *fieldError) Value() interface{} {
method Param (line 232) | func (fe *fieldError) Param() string {
method Kind (line 237) | func (fe *fieldError) Kind() reflect.Kind {
method Type (line 242) | func (fe *fieldError) Type() reflect.Type {
method Error (line 247) | func (fe *fieldError) Error() string {
method Translate (line 256) | func (fe *fieldError) Translate(ut ut.Translator) string {
FILE: field_level.go
type FieldLevel (line 7) | type FieldLevel interface
method Field (line 69) | func (v *validate) Field() reflect.Value {
method FieldName (line 75) | func (v *validate) FieldName() string {
method GetTag (line 80) | func (v *validate) GetTag() string {
method StructFieldName (line 85) | func (v *validate) StructFieldName() string {
method Param (line 90) | func (v *validate) Param() string {
method GetStructFieldOK (line 97) | func (v *validate) GetStructFieldOK() (reflect.Value, reflect.Kind, bool) {
method GetStructFieldOKAdvanced (line 106) | func (v *validate) GetStructFieldOKAdvanced(val reflect.Value, namespace...
method GetStructFieldOK2 (line 112) | func (v *validate) GetStructFieldOK2() (reflect.Value, reflect.Kind, boo...
method GetStructFieldOKAdvanced2 (line 118) | func (v *validate) GetStructFieldOKAdvanced2(val reflect.Value, namespac...
FILE: non-standard/validators/notblank.go
function NotBlank (line 12) | func NotBlank(fl validator.FieldLevel) bool {
FILE: non-standard/validators/notblank_test.go
type test (line 10) | type test struct
function TestNotBlank (line 19) | func TestNotBlank(t *testing.T) {
FILE: options.go
type Option (line 4) | type Option
function WithRequiredStructEnabled (line 12) | func WithRequiredStructEnabled() Option {
function WithPrivateFieldValidation (line 22) | func WithPrivateFieldValidation() Option {
FILE: postcode_regexes.go
function initPostcodes (line 175) | func initPostcodes() {
FILE: regexes.go
constant alphaRegexString (line 9) | alphaRegexString = "^[a-zA-Z]+$"
constant alphaSpaceRegexString (line 10) | alphaSpaceRegexString = "^[a-zA-Z ]+$"
constant alphaNumericRegexString (line 11) | alphaNumericRegexString = "^[a-zA-Z0-9]+$"
constant alphaNumericSpaceRegexString (line 12) | alphaNumericSpaceRegexString = "^[a-zA-Z0-9 ]+$"
constant alphaUnicodeRegexString (line 13) | alphaUnicodeRegexString = "^[\\p{L}]+$"
constant alphaUnicodeNumericRegexString (line 14) | alphaUnicodeNumericRegexString = "^[\\p{L}\\p{N}]+$"
constant numericRegexString (line 15) | numericRegexString = "^[-+]?[0-9]+(?:\\.[0-9]+)?$"
constant numberRegexString (line 16) | numberRegexString = "^[0-9]+$"
constant hexadecimalRegexString (line 17) | hexadecimalRegexString = "^(0[xX])?[0-9a-fA-F]+$"
constant hexColorRegexString (line 18) | hexColorRegexString = "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[...
constant rgbRegexString (line 19) | rgbRegexString = "^rgb\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\d...
constant rgbaRegexString (line 20) | rgbaRegexString = "^rgba\\(\\s*(?:(?:0|[1-9]\\d?|1\\d\\...
constant hslRegexString (line 21) | hslRegexString = "^hsl\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\d...
constant hslaRegexString (line 22) | hslaRegexString = "^hsla\\(\\s*(?:0|[1-9]\\d?|[12]\\d\\...
constant cmykRegexString (line 23) | cmykRegexString = "^cmyk\\((100|[1-9]?\\d)%\\s*,\\s*(10...
constant emailRegexString (line 24) | emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\...
constant e164RegexString (line 25) | e164RegexString = "^\\+?[1-9]\\d{7,14}$"
constant base32RegexString (line 26) | base32RegexString = "^(?:[A-Z2-7]{8})*(?:[A-Z2-7]{2}={6}|...
constant base64RegexString (line 27) | base64RegexString = "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-...
constant base64URLRegexString (line 28) | base64URLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-...
constant base64RawURLRegexString (line 29) | base64RawURLRegexString = "^(?:[A-Za-z0-9-_]{4})*(?:[A-Za-z0-9-...
constant iSBN10RegexString (line 30) | iSBN10RegexString = "^(?:[0-9]{9}X|[0-9]{10})$"
constant iSBN13RegexString (line 31) | iSBN13RegexString = "^(?:(?:97(?:8|9))[0-9]{10})$"
constant iSSNRegexString (line 32) | iSSNRegexString = "^(?:[0-9]{4}-[0-9]{3}[0-9X])$"
constant uUID3RegexString (line 33) | uUID3RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-3[0-9a-f]{3...
constant uUID4RegexString (line 34) | uUID4RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3...
constant uUID5RegexString (line 35) | uUID5RegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3...
constant uUIDRegexString (line 36) | uUIDRegexString = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}...
constant uUID3RFC4122RegexString (line 37) | uUID3RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-3[0-9...
constant uUID4RFC4122RegexString (line 38) | uUID4RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9...
constant uUID5RFC4122RegexString (line 39) | uUID5RFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-5[0-9...
constant uUIDRFC4122RegexString (line 40) | uUIDRFC4122RegexString = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a...
constant uLIDRegexString (line 41) | uLIDRegexString = "^(?i)[A-HJKMNP-TV-Z0-9]{26}$"
constant md4RegexString (line 42) | md4RegexString = "^[0-9a-f]{32}$"
constant md5RegexString (line 43) | md5RegexString = "^[0-9a-f]{32}$"
constant sha256RegexString (line 44) | sha256RegexString = "^[0-9a-f]{64}$"
constant sha384RegexString (line 45) | sha384RegexString = "^[0-9a-f]{96}$"
constant sha512RegexString (line 46) | sha512RegexString = "^[0-9a-f]{128}$"
constant ripemd128RegexString (line 47) | ripemd128RegexString = "^[0-9a-f]{32}$"
constant ripemd160RegexString (line 48) | ripemd160RegexString = "^[0-9a-f]{40}$"
constant tiger128RegexString (line 49) | tiger128RegexString = "^[0-9a-f]{32}$"
constant tiger160RegexString (line 50) | tiger160RegexString = "^[0-9a-f]{40}$"
constant tiger192RegexString (line 51) | tiger192RegexString = "^[0-9a-f]{48}$"
constant aSCIIRegexString (line 52) | aSCIIRegexString = "^[\x00-\x7F]*$"
constant printableASCIIRegexString (line 53) | printableASCIIRegexString = "^[\x20-\x7E]*$"
constant multibyteRegexString (line 54) | multibyteRegexString = "[^\x00-\x7F]"
constant dataURIRegexString (line 55) | dataURIRegexString = `^data:((?:\w+\/(?:([^;]|;[^;]).)+)?)`
constant latitudeRegexString (line 56) | latitudeRegexString = "^[-+]?([1-8]?\\d(\\.\\d+)?|90(\\.0+)...
constant longitudeRegexString (line 57) | longitudeRegexString = "^[-+]?(180(\\.0+)?|((1[0-7]\\d)|([1-...
constant sSNRegexString (line 58) | sSNRegexString = `^[0-9]{3}[ -]?(0[1-9]|[1-9][0-9])[ -...
constant hostnameRegexStringRFC952 (line 59) | hostnameRegexStringRFC952 = `^[a-zA-Z]([a-zA-Z0-9\-]+[\.]?)*[a-zA...
constant hostnameRegexStringRFC1123 (line 60) | hostnameRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62}){...
constant fqdnRegexStringRFC1123 (line 61) | fqdnRegexStringRFC1123 = `^([a-zA-Z0-9]{1}[a-zA-Z0-9-]{0,62})(...
constant btcAddressRegexString (line 62) | btcAddressRegexString = `^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$`
constant btcAddressUpperRegexStringBech32 (line 63) | btcAddressUpperRegexStringBech32 = `^BC1[02-9AC-HJ-NP-Z]{7,76}$`
constant btcAddressLowerRegexStringBech32 (line 64) | btcAddressLowerRegexStringBech32 = `^bc1[02-9ac-hj-np-z]{7,76}$`
constant ethAddressRegexString (line 65) | ethAddressRegexString = `^0x[0-9a-fA-F]{40}$`
constant ethAddressUpperRegexString (line 66) | ethAddressUpperRegexString = `^0x[0-9A-F]{40}$`
constant ethAddressLowerRegexString (line 67) | ethAddressLowerRegexString = `^0x[0-9a-f]{40}$`
constant uRLEncodedRegexString (line 68) | uRLEncodedRegexString = `^(?:[^%]|%[0-9A-Fa-f]{2})*$`
constant hTMLEncodedRegexString (line 69) | hTMLEncodedRegexString = `&#[x]?([0-9a-fA-F]{2})|(>)|(<)|(...
constant hTMLRegexString (line 70) | hTMLRegexString = `<[/]?([a-zA-Z]+).*?>`
constant jWTRegexString (line 71) | jWTRegexString = "^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[...
constant splitParamsRegexString (line 72) | splitParamsRegexString = `'[^']*'|\S+`
constant bic2014RegexString (line 73) | bic2014RegexString = `^[A-Za-z]{6}[A-Za-z0-9]{2}([A-Za-z0-...
constant bic2022RegexString (line 74) | bic2022RegexString = `^[A-Z0-9]{4}[A-Z]{2}[A-Z0-9]{2}(?:[A...
constant semverRegexString (line 75) | semverRegexString = `^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9...
constant dnsRegexStringRFC1035Label (line 76) | dnsRegexStringRFC1035Label = "^[a-z]([-a-z0-9]*[a-z0-9])?$"
constant cveRegexString (line 77) | cveRegexString = `^CVE-(1999|2\d{3})-(0[^0]\d{2}|0\d[^...
constant mongodbIdRegexString (line 78) | mongodbIdRegexString = "^[a-f\\d]{24}$"
constant mongodbConnStringRegexString (line 79) | mongodbConnStringRegexString = "^mongodb(\\+srv)?:\\/\\/(([a-zA-Z\\d...
constant cronRegexString (line 80) | cronRegexString = `(@(annually|yearly|monthly|weekly|da...
constant spicedbIDRegexString (line 81) | spicedbIDRegexString = `^(([a-zA-Z0-9/_|\-=+]{1,})|\*)$`
constant spicedbPermissionRegexString (line 82) | spicedbPermissionRegexString = "^([a-z][a-z0-9_]{1,62}[a-z0-9])?$"
constant spicedbTypeRegexString (line 83) | spicedbTypeRegexString = "^([a-z][a-z0-9_]{1,61}[a-z0-9]/)?[a-...
constant einRegexString (line 84) | einRegexString = "^(\\d{2}-\\d{7})$"
function lazyRegexCompile (line 87) | func lazyRegexCompile(str string) func() *regexp.Regexp {
FILE: struct_level.go
type StructLevelFunc (line 9) | type StructLevelFunc
type StructLevelFuncCtx (line 13) | type StructLevelFuncCtx
function wrapStructLevelFunc (line 16) | func wrapStructLevelFunc(fn StructLevelFunc) StructLevelFuncCtx {
type StructLevel (line 24) | type StructLevel interface
method Top (line 78) | func (v *validate) Top() reflect.Value {
method Parent (line 89) | func (v *validate) Parent() reflect.Value {
method Current (line 94) | func (v *validate) Current() reflect.Value {
method Validator (line 99) | func (v *validate) Validator() *Validate {
method ExtractType (line 104) | func (v *validate) ExtractType(field reflect.Value) (reflect.Value, refl...
method ReportError (line 109) | func (v *validate) ReportError(field interface{}, fieldName, structField...
method ReportValidationErrors (line 161) | func (v *validate) ReportValidationErrors(relativeNamespace, relativeStr...
FILE: translations.go
type TranslationFunc (line 7) | type TranslationFunc
type RegisterTranslationsFunc (line 11) | type RegisterTranslationsFunc
FILE: translations/ar/ar.go
function RegisterDefaultTranslations (line 17) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1409) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1415) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/ar/ar_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/de/de.go
function RegisterDefaultTranslations (line 19) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1469) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1479) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/de/de_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/en/en.go
function RegisterDefaultTranslations (line 19) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1538) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1548) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/en/en_test.go
type Foo (line 13) | type Foo struct
method IsBar (line 15) | func (Foo) IsBar() bool { return false }
function TestTranslations (line 17) | func TestTranslations(t *testing.T) {
FILE: translations/es/es.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1323) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1333) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/es/es_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/fa/fa.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1375) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1385) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/fa/fa_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/fr/fr.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1308) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1318) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/fr/fr_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/id/id.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1543) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1553) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
function translateFuncWithParam (line 1563) | func translateFuncWithParam(ut ut.Translator, fe validator.FieldError) s...
FILE: translations/id/id_test.go
function InitValidator (line 14) | func InitValidator() (*validator.Validate, ut.Translator, error) {
function TestFieldTagsTranslations (line 33) | func TestFieldTagsTranslations(t *testing.T) {
function TestNetworkTagsTranslations (line 217) | func TestNetworkTagsTranslations(t *testing.T) {
function TestStringTagsTranslations (line 394) | func TestStringTagsTranslations(t *testing.T) {
function TestFormatTagsTranslations (line 583) | func TestFormatTagsTranslations(t *testing.T) {
function TestComparisonTagsTranslations (line 942) | func TestComparisonTagsTranslations(t *testing.T) {
function TestOtherTagsTranslations (line 1134) | func TestOtherTagsTranslations(t *testing.T) {
function TestAliasesTagsTranslations (line 1355) | func TestAliasesTagsTranslations(t *testing.T) {
FILE: translations/it/it.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1237) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1247) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
function customTransFuncV1 (line 1257) | func customTransFuncV1(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/it/it_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/ja/ja.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1440) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1450) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/ja/ja_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/ko/ko.go
function RegisterDefaultTranslations (line 19) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1485) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1495) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/ko/ko_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/lv/lv.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1385) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1395) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/lv/lv_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/nl/nl.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1308) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1318) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/nl/nl_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/pl/pl.go
function RegisterDefaultTranslations (line 19) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1202) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1212) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
function translateFuncWithParam (line 1222) | func translateFuncWithParam(ut ut.Translator, fe validator.FieldError) s...
function registerCardinals (line 1232) | func registerCardinals(ut ut.Translator, prefix string) (err error) {
FILE: translations/pl/pl_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/pt/pt.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1344) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1354) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/pt/pt_test.go
function TestTranslations (line 14) | func TestTranslations(t *testing.T) {
FILE: translations/pt_BR/pt_BR.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1321) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1331) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/pt_BR/pt_BR_test.go
type Foo (line 13) | type Foo struct
method IsBar (line 15) | func (Foo) IsBar() bool { return false }
function TestTranslations (line 17) | func TestTranslations(t *testing.T) {
FILE: translations/ru/ru.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1431) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1441) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/ru/ru_test.go
function TestTranslations (line 15) | func TestTranslations(t *testing.T) {
FILE: translations/th/th.go
function RegisterDefaultTranslations (line 19) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1353) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1363) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/th/th_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/tr/tr.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1312) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1322) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/tr/tr_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/uk/uk.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1195) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1205) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
function translateFuncWithParam (line 1215) | func translateFuncWithParam(ut ut.Translator, fe validator.FieldError) s...
function registerCardinals (line 1225) | func registerCardinals(ut ut.Translator, prefix string) (err error) {
FILE: translations/uk/uk_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/vi/vi.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1375) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1385) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/vi/vi_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/zh/zh.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1450) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1460) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/zh/zh_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: translations/zh_tw/zh_tw.go
function RegisterDefaultTranslations (line 18) | func RegisterDefaultTranslations(v *validator.Validate, trans ut.Transla...
function registrationFunc (line 1381) | func registrationFunc(tag string, translation string, override bool) val...
function translateFunc (line 1391) | func translateFunc(ut ut.Translator, fe validator.FieldError) string {
FILE: translations/zh_tw/zh_tw_test.go
function TestTranslations (line 13) | func TestTranslations(t *testing.T) {
FILE: util.go
type Valuer (line 14) | type Valuer interface
method extractTypeInternal (line 22) | func (v *validate) extractTypeInternal(current reflect.Value, nullable b...
method getStructFieldOKInternal (line 89) | func (v *validate) getStructFieldOKInternal(val reflect.Value, namespace...
function asInt (line 252) | func asInt(param string) int64 {
function asIntFromTimeDuration (line 261) | func asIntFromTimeDuration(param string) int64 {
function asIntFromType (line 272) | func asIntFromType(t reflect.Type, param string) int64 {
function asUint (line 283) | func asUint(param string) uint64 {
function asFloat64 (line 292) | func asFloat64(param string) float64 {
function asFloat32 (line 300) | func asFloat32(param string) float64 {
function asBool (line 308) | func asBool(param string) bool {
function panicIf (line 315) | func panicIf(err error) {
function fieldMatchesRegexByStringerValOrString (line 323) | func fieldMatchesRegexByStringerValOrString(regexFn func() *regexp.Regex...
FILE: validator.go
type validate (line 12) | type validate struct
method validateStruct (line 34) | func (v *validate) validateStruct(ctx context.Context, parent reflect....
method traverseField (line 90) | func (v *validate) traverseField(ctx context.Context, parent reflect.V...
function getValue (line 502) | func getValue(val reflect.Value) interface{} {
FILE: validator_instance.go
constant defaultTagName (line 16) | defaultTagName = "validate"
constant utf8HexComma (line 17) | utf8HexComma = "0x2C"
constant utf8Pipe (line 18) | utf8Pipe = "0x7C"
constant tagSeparator (line 19) | tagSeparator = ","
constant orSeparator (line 20) | orSeparator = "|"
constant tagKeySeparator (line 21) | tagKeySeparator = "="
constant structOnlyTag (line 22) | structOnlyTag = "structonly"
constant noStructLevelTag (line 23) | noStructLevelTag = "nostructlevel"
constant omitzero (line 24) | omitzero = "omitzero"
constant omitempty (line 25) | omitempty = "omitempty"
constant omitnil (line 26) | omitnil = "omitnil"
constant isdefault (line 27) | isdefault = "isdefault"
constant requiredWithoutAllTag (line 28) | requiredWithoutAllTag = "required_without_all"
constant requiredWithoutTag (line 29) | requiredWithoutTag = "required_without"
constant requiredWithTag (line 30) | requiredWithTag = "required_with"
constant requiredWithAllTag (line 31) | requiredWithAllTag = "required_with_all"
constant requiredIfTag (line 32) | requiredIfTag = "required_if"
constant requiredUnlessTag (line 33) | requiredUnlessTag = "required_unless"
constant skipUnlessTag (line 34) | skipUnlessTag = "skip_unless"
constant excludedWithoutAllTag (line 35) | excludedWithoutAllTag = "excluded_without_all"
constant excludedWithoutTag (line 36) | excludedWithoutTag = "excluded_without"
constant excludedWithTag (line 37) | excludedWithTag = "excluded_with"
constant excludedWithAllTag (line 38) | excludedWithAllTag = "excluded_with_all"
constant excludedIfTag (line 39) | excludedIfTag = "excluded_if"
constant excludedUnlessTag (line 40) | excludedUnlessTag = "excluded_unless"
constant skipValidationTag (line 41) | skipValidationTag = "-"
constant diveTag (line 42) | diveTag = "dive"
constant keysTag (line 43) | keysTag = "keys"
constant endKeysTag (line 44) | endKeysTag = "endkeys"
constant requiredTag (line 45) | requiredTag = "required"
constant namespaceSeparator (line 46) | namespaceSeparator = "."
constant leftBracket (line 47) | leftBracket = "["
constant rightBracket (line 48) | rightBracket = "]"
constant restrictedTagChars (line 49) | restrictedTagChars = ".[],|=+()`~!@#$%^&*\\\"/?<>{}"
constant restrictedAliasErr (line 50) | restrictedAliasErr = "Alias '%s' either contains restricted character...
constant restrictedTagErr (line 51) | restrictedTagErr = "Tag '%s' either contains restricted characters ...
type FilterFunc (line 67) | type FilterFunc
type CustomTypeFunc (line 72) | type CustomTypeFunc
type TagNameFunc (line 75) | type TagNameFunc
type internalValidationFuncWrapper (line 77) | type internalValidationFuncWrapper struct
type Validate (line 83) | type Validate struct
method SetTagName (line 158) | func (v *Validate) SetTagName(name string) {
method ValidateMapCtx (line 164) | func (v Validate) ValidateMapCtx(ctx context.Context, data map[string]...
method ValidateMap (line 194) | func (v *Validate) ValidateMap(data map[string]interface{}, rules map[...
method RegisterTagNameFunc (line 210) | func (v *Validate) RegisterTagNameFunc(fn TagNameFunc) {
method RegisterValidation (line 220) | func (v *Validate) RegisterValidation(tag string, fn Func, callValidat...
method RegisterValidationCtx (line 226) | func (v *Validate) RegisterValidationCtx(tag string, fn FuncCtx, callV...
method RegisterAlias (line 239) | func (v *Validate) RegisterAlias(alias, tags string) {
method RegisterStructValidation (line 253) | func (v *Validate) RegisterStructValidation(fn StructLevelFunc, types ...
method RegisterStructValidationCtx (line 262) | func (v *Validate) RegisterStructValidationCtx(fn StructLevelFuncCtx, ...
method RegisterStructValidationMapRules (line 281) | func (v *Validate) RegisterStructValidationMapRules(rules map[string]s...
method RegisterCustomTypeFunc (line 308) | func (v *Validate) RegisterCustomTypeFunc(fn CustomTypeFunc, types ......
method RegisterTranslation (line 321) | func (v *Validate) RegisterTranslation(tag string, trans ut.Translator...
method Struct (line 345) | func (v *Validate) Struct(s interface{}) error {
method StructCtx (line 354) | func (v *Validate) StructCtx(ctx context.Context, s interface{}) (err ...
method StructFiltered (line 389) | func (v *Validate) StructFiltered(s interface{}, fn FilterFunc) error {
method StructFilteredCtx (line 399) | func (v *Validate) StructFilteredCtx(ctx context.Context, s interface{...
method StructPartial (line 436) | func (v *Validate) StructPartial(s interface{}, fields ...string) error {
method StructPartialCtx (line 447) | func (v *Validate) StructPartialCtx(ctx context.Context, s interface{}...
method StructExcept (line 522) | func (v *Validate) StructExcept(s interface{}, fields ...string) error {
method StructExceptCtx (line 533) | func (v *Validate) StructExceptCtx(ctx context.Context, s interface{},...
method Var (line 593) | func (v *Validate) Var(field interface{}, tag string) error {
method VarCtx (line 611) | func (v *Validate) VarCtx(ctx context.Context, field interface{}, tag ...
method VarWithValue (line 646) | func (v *Validate) VarWithValue(field interface{}, other interface{}, ...
method VarWithValueCtx (line 665) | func (v *Validate) VarWithValueCtx(ctx context.Context, field interfac...
method VarWithKey (line 697) | func (v *Validate) VarWithKey(key string, field interface{}, tag strin...
method VarWithKeyCtx (line 715) | func (v *Validate) VarWithKeyCtx(ctx context.Context, key string, fiel...
method registerValidation (line 742) | func (v *Validate) registerValidation(tag string, fn FuncCtx, bakedIn ...
function New (line 106) | func New(options ...Option) *Validate {
FILE: validator_test.go
type I (line 49) | type I interface
type Impl (line 53) | type Impl struct
method Foo (line 57) | func (i *Impl) Foo() string {
type SubTest (line 61) | type SubTest struct
type TestInterface (line 65) | type TestInterface struct
type TestString (line 69) | type TestString struct
type TestUint64 (line 90) | type TestUint64 struct
type TestFloat64 (line 99) | type TestFloat64 struct
type TestSlice (line 109) | type TestSlice struct
function AssertError (line 118) | func AssertError(t *testing.T, err error, nsKey, structNsKey, field, str...
function AssertDeepError (line 139) | func AssertDeepError(t *testing.T, err error, nsKey, structNsKey, field,...
function getError (line 159) | func getError(err error, nsKey, structNsKey string) FieldError {
type valuer (line 174) | type valuer struct
method Value (line 178) | func (v valuer) Value() (driver.Value, error) {
type MadeUpCustomType (line 191) | type MadeUpCustomType struct
function ValidateCustomType (line 196) | func ValidateCustomType(field reflect.Value) interface{} {
function OverrideIntTypeForSomeReason (line 208) | func OverrideIntTypeForSomeReason(field reflect.Value) interface{} {
type CustomMadeUpStruct (line 222) | type CustomMadeUpStruct struct
function ValidateValuerType (line 227) | func ValidateValuerType(field reflect.Value) interface{} {
type TestPartial (line 241) | type TestPartial struct
type TestStruct (line 259) | type TestStruct struct
function StructValidationTestStructSuccess (line 263) | func StructValidationTestStructSuccess(sl StructLevel) {
function StructValidationTestStruct (line 271) | func StructValidationTestStruct(sl StructLevel) {
function StructValidationNoTestStructCustomName (line 279) | func StructValidationNoTestStructCustomName(sl StructLevel) {
function StructValidationTestStructInvalid (line 287) | func StructValidationTestStructInvalid(sl StructLevel) {
function StructValidationTestStructReturnValidationErrors (line 295) | func StructValidationTestStructReturnValidationErrors(sl StructLevel) {
function StructValidationTestStructReturnValidationErrors2 (line 306) | func StructValidationTestStructReturnValidationErrors2(sl StructLevel) {
type TestStructReturnValidationErrorsInner2 (line 317) | type TestStructReturnValidationErrorsInner2 struct
type TestStructReturnValidationErrorsInner1 (line 321) | type TestStructReturnValidationErrorsInner1 struct
type TestStructReturnValidationErrors (line 325) | type TestStructReturnValidationErrors struct
type StructLevelInvalidErr (line 329) | type StructLevelInvalidErr struct
function StructLevelInvalidError (line 333) | func StructLevelInvalidError(sl StructLevel) {
function stringPtr (line 342) | func stringPtr(v string) *string {
function intPtr (line 346) | func intPtr(v int) *int {
function float64Ptr (line 350) | func float64Ptr(v float64) *float64 {
function TestStructLevelInvalidError (line 354) | func TestStructLevelInvalidError(t *testing.T) {
function TestNameNamespace (line 377) | func TestNameNamespace(t *testing.T) {
function TestAnonymous (line 425) | func TestAnonymous(t *testing.T) {
function TestAnonymousSameStructDifferentTags (line 492) | func TestAnonymousSameStructDifferentTags(t *testing.T) {
function TestStructLevelReturnValidationErrors (line 536) | func TestStructLevelReturnValidationErrors(t *testing.T) {
function TestStructLevelReturnValidationErrorsWithJSON (line 565) | func TestStructLevelReturnValidationErrorsWithJSON(t *testing.T) {
function TestStructLevelValidations (line 621) | func TestStructLevelValidations(t *testing.T) {
function TestAliasTags (line 654) | func TestAliasTags(t *testing.T) {
function TestAliasWithOrOperator (line 701) | func TestAliasWithOrOperator(t *testing.T) {
function TestNilValidator (line 763) | func TestNilValidator(t *testing.T) {
function TestStructPartial (line 785) | func TestStructPartial(t *testing.T) {
function TestCrossStructLteFieldValidation (line 1029) | func TestCrossStructLteFieldValidation(t *testing.T) {
function TestCrossStructLtFieldValidation (line 1196) | func TestCrossStructLtFieldValidation(t *testing.T) {
function TestCrossStructGteFieldValidation (line 1352) | func TestCrossStructGteFieldValidation(t *testing.T) {
function TestCrossStructGtFieldValidation (line 1518) | func TestCrossStructGtFieldValidation(t *testing.T) {
function TestCrossStructNeFieldValidation (line 1674) | func TestCrossStructNeFieldValidation(t *testing.T) {
function TestCrossStructEqFieldValidation (line 1846) | func TestCrossStructEqFieldValidation(t *testing.T) {
function TestCrossNamespaceFieldValidation (line 2016) | func TestCrossNamespaceFieldValidation(t *testing.T) {
function TestExistsValidation (line 2257) | func TestExistsValidation(t *testing.T) {
function TestSQLValue2Validation (line 2287) | func TestSQLValue2Validation(t *testing.T) {
function TestSQLValueValidation (line 2337) | func TestSQLValueValidation(t *testing.T) {
function TestMACValidation (line 2394) | func TestMACValidation(t *testing.T) {
function TestIPValidation (line 2430) | func TestIPValidation(t *testing.T) {
function TestIPv6Validation (line 2470) | func TestIPv6Validation(t *testing.T) {
function TestIPv4Validation (line 2509) | func TestIPv4Validation(t *testing.T) {
function TestCIDRValidation (line 2548) | func TestCIDRValidation(t *testing.T) {
function TestCIDRv6Validation (line 2590) | func TestCIDRv6Validation(t *testing.T) {
function TestCIDRv4Validation (line 2632) | func TestCIDRv4Validation(t *testing.T) {
function TestTCPAddrValidation (line 2681) | func TestTCPAddrValidation(t *testing.T) {
function TestTCP6AddrValidation (line 2715) | func TestTCP6AddrValidation(t *testing.T) {
function TestTCP4AddrValidation (line 2749) | func TestTCP4AddrValidation(t *testing.T) {
function TestUDPAddrValidation (line 2784) | func TestUDPAddrValidation(t *testing.T) {
function TestUDP6AddrValidation (line 2818) | func TestUDP6AddrValidation(t *testing.T) {
function TestUDP4AddrValidation (line 2852) | func TestUDP4AddrValidation(t *testing.T) {
function TestIPAddrValidation (line 2887) | func TestIPAddrValidation(t *testing.T) {
function TestIP6AddrValidation (line 2921) | func TestIP6AddrValidation(t *testing.T) {
function TestIP4AddrValidation (line 2955) | func TestIP4AddrValidation(t *testing.T) {
function TestUnixAddrValidation (line 2990) | func TestUnixAddrValidation(t *testing.T) {
function TestUnixDomainSocketExistsValidation (line 3021) | func TestUnixDomainSocketExistsValidation(t *testing.T) {
function TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation (line 3113) | func TestSliceMapArrayChanFuncPtrInterfaceRequiredValidation(t *testing....
function TestDatePtrValidationIssueValidation (line 3190) | func TestDatePtrValidationIssueValidation(t *testing.T) {
function TestCommaAndPipeObfuscationValidation (line 3203) | func TestCommaAndPipeObfuscationValidation(t *testing.T) {
function TestBadKeyValidation (line 3217) | func TestBadKeyValidation(t *testing.T) {
function TestInterfaceErrValidation (line 3241) | func TestInterfaceErrValidation(t *testing.T) {
function TestMapDiveValidation (line 3414) | func TestMapDiveValidation(t *testing.T) {
function TestArrayDiveValidation (line 3551) | func TestArrayDiveValidation(t *testing.T) {
function TestNilStructPointerValidation (line 3769) | func TestNilStructPointerValidation(t *testing.T) {
function TestSSNValidation (line 3863) | func TestSSNValidation(t *testing.T) {
function TestLongitudeValidation (line 3897) | func TestLongitudeValidation(t *testing.T) {
function TestLatitudeValidation (line 3938) | func TestLatitudeValidation(t *testing.T) {
function TestDataURIValidation (line 3979) | func TestDataURIValidation(t *testing.T) {
function TestMultibyteValidation (line 4026) | func TestMultibyteValidation(t *testing.T) {
function TestPrintableASCIIValidation (line 4065) | func TestPrintableASCIIValidation(t *testing.T) {
function TestASCIIValidation (line 4107) | func TestASCIIValidation(t *testing.T) {
function TestUUID5Validation (line 4148) | func TestUUID5Validation(t *testing.T) {
function TestUUID4Validation (line 4183) | func TestUUID4Validation(t *testing.T) {
function TestUUID3Validation (line 4218) | func TestUUID3Validation(t *testing.T) {
type uuidTestType (line 4252) | type uuidTestType struct
method String (line 4256) | func (u uuidTestType) String() string {
type uuidAlias (line 4260) | type uuidAlias
method String (line 4262) | func (u uuidAlias) String() string {
function TestUUIDValidation (line 4271) | func TestUUIDValidation(t *testing.T) {
function TestUUID5RFC4122Validation (line 4333) | func TestUUID5RFC4122Validation(t *testing.T) {
function TestUUID4RFC4122Validation (line 4368) | func TestUUID4RFC4122Validation(t *testing.T) {
function TestUUID3RFC4122Validation (line 4403) | func TestUUID3RFC4122Validation(t *testing.T) {
function TestUUIDRFC4122Validation (line 4437) | func TestUUIDRFC4122Validation(t *testing.T) {
function TestULIDValidation (line 4474) | func TestULIDValidation(t *testing.T) {
function TestMD4Validation (line 4513) | func TestMD4Validation(t *testing.T) {
function TestMD5Validation (line 4548) | func TestMD5Validation(t *testing.T) {
function TestSHA256Validation (line 4583) | func TestSHA256Validation(t *testing.T) {
function TestSHA384Validation (line 4617) | func TestSHA384Validation(t *testing.T) {
function TestSHA512Validation (line 4652) | func TestSHA512Validation(t *testing.T) {
function TestRIPEMD128Validation (line 4687) | func TestRIPEMD128Validation(t *testing.T) {
function TestRIPEMD160Validation (line 4722) | func TestRIPEMD160Validation(t *testing.T) {
function TestTIGER128Validation (line 4757) | func TestTIGER128Validation(t *testing.T) {
function TestTIGER160Validation (line 4792) | func TestTIGER160Validation(t *testing.T) {
function TestTIGER192Validation (line 4827) | func TestTIGER192Validation(t *testing.T) {
function TestISBNValidation (line 4862) | func TestISBNValidation(t *testing.T) {
function TestISBN13Validation (line 4901) | func TestISBN13Validation(t *testing.T) {
function TestISBN10Validation (line 4939) | func TestISBN10Validation(t *testing.T) {
function TestISSNValidation (line 4978) | func TestISSNValidation(t *testing.T) {
function TestExcludesRuneValidation (line 5014) | func TestExcludesRuneValidation(t *testing.T) {
function TestExcludesAllValidation (line 5041) | func TestExcludesAllValidation(t *testing.T) {
function TestExcludesValidation (line 5086) | func TestExcludesValidation(t *testing.T) {
function TestContainsRuneValidation (line 5113) | func TestContainsRuneValidation(t *testing.T) {
function TestContainsAnyValidation (line 5140) | func TestContainsAnyValidation(t *testing.T) {
function TestContainsValidation (line 5167) | func TestContainsValidation(t *testing.T) {
function TestIsNeFieldValidation (line 5194) | func TestIsNeFieldValidation(t *testing.T) {
function TestIsNeValidation (line 5354) | func TestIsNeValidation(t *testing.T) {
function TestIsNeIgnoreCaseValidation (line 5434) | func TestIsNeIgnoreCaseValidation(t *testing.T) {
function TestIsEqFieldValidation (line 5452) | func TestIsEqFieldValidation(t *testing.T) {
function TestIsEqFieldValidationWithAliasTime (line 5625) | func TestIsEqFieldValidationWithAliasTime(t *testing.T) {
function TestIsEqValidation (line 5647) | func TestIsEqValidation(t *testing.T) {
function TestIsEqIgnoreCaseValidation (line 5729) | func TestIsEqIgnoreCaseValidation(t *testing.T) {
function TestOneOfValidation (line 5746) | func TestOneOfValidation(t *testing.T) {
function TestOneOfCIValidation (line 5809) | func TestOneOfCIValidation(t *testing.T) {
function TestBase32Validation (line 5885) | func TestBase32Validation(t *testing.T) {
function TestBase64Validation (line 5919) | func TestBase64Validation(t *testing.T) {
function TestBase64URLValidation (line 5942) | func TestBase64URLValidation(t *testing.T) {
function TestBase64RawURLValidation (line 5989) | func TestBase64RawURLValidation(t *testing.T) {
function TestFileValidation (line 6036) | func TestFileValidation(t *testing.T) {
function TestImageValidation (line 6069) | func TestImageValidation(t *testing.T) {
function TestFilePathValidation (line 6181) | func TestFilePathValidation(t *testing.T) {
function TestEthereumAddressValidation (line 6215) | func TestEthereumAddressValidation(t *testing.T) {
function TestEthereumAddressChecksumValidation (line 6267) | func TestEthereumAddressChecksumValidation(t *testing.T) {
function TestBitcoinAddressValidation (line 6316) | func TestBitcoinAddressValidation(t *testing.T) {
function TestBitcoinBech32AddressValidation (line 6424) | func TestBitcoinBech32AddressValidation(t *testing.T) {
function TestNoStructLevelValidation (line 6473) | func TestNoStructLevelValidation(t *testing.T) {
function TestStructOnlyValidation (line 6533) | func TestStructOnlyValidation(t *testing.T) {
function TestGtField (line 6621) | func TestGtField(t *testing.T) {
function TestLtField (line 6850) | func TestLtField(t *testing.T) {
function TestFieldContains (line 7059) | func TestFieldContains(t *testing.T) {
function TestFieldExcludes (line 7108) | func TestFieldExcludes(t *testing.T) {
function TestContainsAndExcludes (line 7155) | func TestContainsAndExcludes(t *testing.T) {
function TestLteField (line 7182) | func TestLteField(t *testing.T) {
function TestGteField (line 7392) | func TestGteField(t *testing.T) {
function TestValidateByTagAndValue (line 7602) | func TestValidateByTagAndValue(t *testing.T) {
function TestAddFunctions (line 7627) | func TestAddFunctions(t *testing.T) {
function TestChangeTag (line 7656) | func TestChangeTag(t *testing.T) {
function TestUnexposedStruct (line 7677) | func TestUnexposedStruct(t *testing.T) {
function TestBadParams (line 7696) | func TestBadParams(t *testing.T) {
function TestLength (line 7712) | func TestLength(t *testing.T) {
function TestIsGt (line 7718) | func TestIsGt(t *testing.T) {
function TestIsGte (line 7817) | func TestIsGte(t *testing.T) {
function TestMinValidation (line 7900) | func TestMinValidation(t *testing.T) {
function TestMaxValidation (line 7950) | func TestMaxValidation(t *testing.T) {
function TestMinMaxValidation (line 8000) | func TestMinMaxValidation(t *testing.T) {
function TestLenValidation (line 8066) | func TestLenValidation(t *testing.T) {
function TestIsLt (line 8118) | func TestIsLt(t *testing.T) {
function TestIsLte (line 8219) | func TestIsLte(t *testing.T) {
function TestUrnRFC2141 (line 8302) | func TestUrnRFC2141(t *testing.T) {
function TestUrl (line 8377) | func TestUrl(t *testing.T) {
function TestHttpUrl (line 8453) | func TestHttpUrl(t *testing.T) {
function TestHttpsUrl (line 8527) | func TestHttpsUrl(t *testing.T) {
function TestUri (line 8601) | func TestUri(t *testing.T) {
function TestOrTag (line 8666) | func TestOrTag(t *testing.T) {
function TestCmyk (line 8732) | func TestCmyk(t *testing.T) {
function TestHsla (line 8773) | func TestHsla(t *testing.T) {
function TestHsl (line 8819) | func TestHsl(t *testing.T) {
function TestRgba (line 8856) | func TestRgba(t *testing.T) {
function TestRgb (line 8901) | func TestRgb(t *testing.T) {
function TestE164 (line 8942) | func TestE164(t *testing.T) {
function TestEmail (line 8973) | func TestEmail(t *testing.T) {
function TestHexColor (line 9054) | func TestHexColor(t *testing.T) {
function TestHexadecimal (line 9081) | func TestHexadecimal(t *testing.T) {
function TestNumber (line 9107) | func TestNumber(t *testing.T) {
function TestNumeric (line 9154) | func TestNumeric(t *testing.T) {
function TestBoolean (line 9196) | func TestBoolean(t *testing.T) {
function TestAlphaNumeric (line 9234) | func TestAlphaNumeric(t *testing.T) {
function TestAlpha (line 9251) | func TestAlpha(t *testing.T) {
function TestAlphaSpace (line 9283) | func TestAlphaSpace(t *testing.T) {
function TestAlphaNumericSpace (line 9308) | func TestAlphaNumericSpace(t *testing.T) {
function TestStructStringValidation (line 9375) | func TestStructStringValidation(t *testing.T) {
function TestStructInt32Validation (line 9459) | func TestStructInt32Validation(t *testing.T) {
function TestStructUint64Validation (line 9522) | func TestStructUint64Validation(t *testing.T) {
function TestStructFloat64Validation (line 9561) | func TestStructFloat64Validation(t *testing.T) {
function TestStructSliceValidation (line 9600) | func TestStructSliceValidation(t *testing.T) {
function TestInvalidStruct (line 9652) | func TestInvalidStruct(t *testing.T) {
function TestInvalidValidatorFunction (line 9676) | func TestInvalidValidatorFunction(t *testing.T) {
function TestCustomFieldName (line 9686) | func TestCustomFieldName(t *testing.T) {
function TestMultipleRecursiveExtractStructCache (line 9729) | func TestMultipleRecursiveExtractStructCache(t *testing.T) {
function TestPointerAndOmitEmpty (line 9757) | func TestPointerAndOmitEmpty(t *testing.T) {
function TestRequired (line 9802) | func TestRequired(t *testing.T) {
function TestBoolEqual (line 9825) | func TestBoolEqual(t *testing.T) {
function TestTranslations (line 9843) | func TestTranslations(t *testing.T) {
function TestTranslationErrors (line 9945) | func TestTranslationErrors(t *testing.T) {
function TestStructFiltered (line 9976) | func TestStructFiltered(t *testing.T) {
function TestRequiredPtr (line 10139) | func TestRequiredPtr(t *testing.T) {
function TestAlphaUnicodeValidation (line 10231) | func TestAlphaUnicodeValidation(t *testing.T) {
function TestAlphanumericUnicodeValidation (line 10271) | func TestAlphanumericUnicodeValidation(t *testing.T) {
function TestArrayStructNamespace (line 10312) | func TestArrayStructNamespace(t *testing.T) {
function TestMapStructNamespace (line 10340) | func TestMapStructNamespace(t *testing.T) {
function TestFieldLevelName (line 10371) | func TestFieldLevelName(t *testing.T) {
function TestValidateStructRegisterCtx (line 10446) | func TestValidateStructRegisterCtx(t *testing.T) {
function TestHostnameRFC952Validation (line 10479) | func TestHostnameRFC952Validation(t *testing.T) {
function TestHostnameRFC1123Validation (line 10532) | func TestHostnameRFC1123Validation(t *testing.T) {
function TestHostnameRFC1123AliasValidation (line 10580) | func TestHostnameRFC1123AliasValidation(t *testing.T) {
function TestFQDNValidation (line 10629) | func TestFQDNValidation(t *testing.T) {
function TestIsDefault (line 10678) | func TestIsDefault(t *testing.T) {
function TestUniqueValidation (line 10733) | func TestUniqueValidation(t *testing.T) {
function TestUniqueValidationStructSlice (line 10849) | func TestUniqueValidationStructSlice(t *testing.T) {
function TestUniqueValidationStructPtrSlice (line 10891) | func TestUniqueValidationStructPtrSlice(t *testing.T) {
function TestUniqueValidationNilPtrSlice (line 10934) | func TestUniqueValidationNilPtrSlice(t *testing.T) {
function TestHTMLValidation (line 11042) | func TestHTMLValidation(t *testing.T) {
function TestHTMLEncodedValidation (line 11080) | func TestHTMLEncodedValidation(t *testing.T) {
function TestURLEncodedValidation (line 11125) | func TestURLEncodedValidation(t *testing.T) {
function TestKeys (line 11165) | func TestKeys(t *testing.T) {
function TestKeysCustomValidation (line 11271) | func TestKeysCustomValidation(t *testing.T) {
function TestKeyOrs (line 11333) | func TestKeyOrs(t *testing.T) {
function TestStructLevelValidationsPointerPassing (line 11398) | func TestStructLevelValidationsPointerPassing(t *testing.T) {
function TestDirValidation (line 11411) | func TestDirValidation(t *testing.T) {
function TestDirPathValidation (line 11446) | func TestDirPathValidation(t *testing.T) {
function TestStartsWithValidation (line 11480) | func TestStartsWithValidation(t *testing.T) {
function TestEndsWithValidation (line 11507) | func TestEndsWithValidation(t *testing.T) {
function TestRequiredIf (line 11534) | func TestRequiredIf(t *testing.T) {
function TestRequiredIfDuplicateParams (line 11612) | func TestRequiredIfDuplicateParams(t *testing.T) {
function TestRequiredUnless (line 11655) | func TestRequiredUnless(t *testing.T) {
function TestSkipUnless (line 11776) | func TestSkipUnless(t *testing.T) {
function TestRequiredWith (line 11867) | func TestRequiredWith(t *testing.T) {
function TestExcludedWith (line 11930) | func TestExcludedWith(t *testing.T) {
function TestExcludedWithout (line 12030) | func TestExcludedWithout(t *testing.T) {
function TestExcludedWithAll (line 12124) | func TestExcludedWithAll(t *testing.T) {
function TestExcludedWithoutAll (line 12229) | func TestExcludedWithoutAll(t *testing.T) {
function TestRequiredWithAll (line 12326) | func TestRequiredWithAll(t *testing.T) {
function TestRequiredWithout (line 12388) | func TestRequiredWithout(t *testing.T) {
function TestRequiredWithoutAll (line 12487) | func TestRequiredWithoutAll(t *testing.T) {
function TestExcludedIf (line 12540) | func TestExcludedIf(t *testing.T) {
function TestExcludedUnless (line 12697) | func TestExcludedUnless(t *testing.T) {
function TestLookup (line 12827) | func TestLookup(t *testing.T) {
function TestAbilityToValidateNils (line 12841) | func TestAbilityToValidateNils(t *testing.T) {
function TestRequiredWithoutPointers (line 12865) | func TestRequiredWithoutPointers(t *testing.T) {
function TestRequiredWithoutAllPointers (line 12890) | func TestRequiredWithoutAllPointers(t *testing.T) {
function TestGetTag (line 12915) | func TestGetTag(t *testing.T) {
function TestJSONValidation (line 12934) | func TestJSONValidation(t *testing.T) {
function TestJWTValidation (line 13009) | func TestJWTValidation(t *testing.T) {
function Test_hostnameport_validator (line 13044) | func Test_hostnameport_validator(t *testing.T) {
function Test_port_validator (line 13074) | func Test_port_validator(t *testing.T) {
function TestLowercaseValidation (line 13100) | func TestLowercaseValidation(t *testing.T) {
function TestUppercaseValidation (line 13136) | func TestUppercaseValidation(t *testing.T) {
function TestDatetimeValidation (line 13172) | func TestDatetimeValidation(t *testing.T) {
function TestIsIso3166Alpha2Validation (line 13208) | func TestIsIso3166Alpha2Validation(t *testing.T) {
function TestIsIso3166Alpha2EUValidation (line 13235) | func TestIsIso3166Alpha2EUValidation(t *testing.T) {
function TestIsIso31662Validation (line 13261) | func TestIsIso31662Validation(t *testing.T) {
function TestIsIso3166Alpha3Validation (line 13288) | func TestIsIso3166Alpha3Validation(t *testing.T) {
function TestIsIso3166Alpha3EUValidation (line 13315) | func TestIsIso3166Alpha3EUValidation(t *testing.T) {
function TestIsIso3166AlphaNumericValidation (line 13342) | func TestIsIso3166AlphaNumericValidation(t *testing.T) {
function TestIsIso3166AlphaNumericEUValidation (line 13376) | func TestIsIso3166AlphaNumericEUValidation(t *testing.T) {
function TestCountryCodeValidation (line 13408) | func TestCountryCodeValidation(t *testing.T) {
function TestEUCountryCodeValidation (line 13440) | func TestEUCountryCodeValidation(t *testing.T) {
function TestIsIso4217Validation (line 13472) | func TestIsIso4217Validation(t *testing.T) {
function TestIsIso4217NumericValidation (line 13508) | func TestIsIso4217NumericValidation(t *testing.T) {
function TestTimeZoneValidation (line 13543) | func TestTimeZoneValidation(t *testing.T) {
function TestDurationType (line 13583) | func TestDurationType(t *testing.T) {
function TestBCP47LanguageTagValidation (line 13626) | func TestBCP47LanguageTagValidation(t *testing.T) {
function TestBicIso2014FormatValidation (line 13668) | func TestBicIso2014FormatValidation(t *testing.T) {
function TestBicIso2022FormatValidation (line 13708) | func TestBicIso2022FormatValidation(t *testing.T) {
function TestSemverFormatValidation (line 13782) | func TestSemverFormatValidation(t *testing.T) {
function TestCveFormatValidation (line 13859) | func TestCveFormatValidation(t *testing.T) {
function TestRFC1035LabelFormatValidation (line 13902) | func TestRFC1035LabelFormatValidation(t *testing.T) {
function TestPostCodeByIso3166Alpha2 (line 13943) | func TestPostCodeByIso3166Alpha2(t *testing.T) {
function TestPostCodeByIso3166Alpha2Field (line 13990) | func TestPostCodeByIso3166Alpha2Field(t *testing.T) {
function TestPostCodeByIso3166Alpha2Field_WrongField (line 14023) | func TestPostCodeByIso3166Alpha2Field_WrongField(t *testing.T) {
function TestPostCodeByIso3166Alpha2Field_MissingParam (line 14034) | func TestPostCodeByIso3166Alpha2Field_MissingParam(t *testing.T) {
function TestPostCodeByIso3166Alpha2Field_InvalidKind (line 14045) | func TestPostCodeByIso3166Alpha2Field_InvalidKind(t *testing.T) {
function TestValidate_ValidateMapCtx (line 14057) | func TestValidate_ValidateMapCtx(t *testing.T) {
function TestValidate_ValidateMapCtxWithKeys (line 14147) | func TestValidate_ValidateMapCtxWithKeys(t *testing.T) {
function TestValidateMapWithCrossFieldValidators (line 14231) | func TestValidateMapWithCrossFieldValidators(t *testing.T) {
function TestValidate_VarWithKey (line 14293) | func TestValidate_VarWithKey(t *testing.T) {
function TestValidate_VarWithKeyCtx (line 14303) | func TestValidate_VarWithKeyCtx(t *testing.T) {
function TestMongoDBObjectIDFormatValidation (line 14313) | func TestMongoDBObjectIDFormatValidation(t *testing.T) {
function TestMongoDBConnectionStringFormatValidation (line 14349) | func TestMongoDBConnectionStringFormatValidation(t *testing.T) {
function TestSpiceDBValueFormatValidation (line 14402) | func TestSpiceDBValueFormatValidation(t *testing.T) {
function TestCreditCardFormatValidation (line 14476) | func TestCreditCardFormatValidation(t *testing.T) {
function TestLuhnChecksumValidation (line 14516) | func TestLuhnChecksumValidation(t *testing.T) {
function TestMultiOrOperatorGroup (line 14561) | func TestMultiOrOperatorGroup(t *testing.T) {
function TestCronExpressionValidation (line 14585) | func TestCronExpressionValidation(t *testing.T) {
function TestNestedStructValidation (line 14620) | func TestNestedStructValidation(t *testing.T) {
function TestTimeRequired (line 14797) | func TestTimeRequired(t *testing.T) {
function TestOmitNilAndRequired (line 14820) | func TestOmitNilAndRequired(t *testing.T) {
function TestOmitZero (line 14864) | func TestOmitZero(t *testing.T) {
function TestEINStringValidation (line 14915) | func TestEINStringValidation(t *testing.T) {
function TestPrivateFieldsStruct (line 14945) | func TestPrivateFieldsStruct(t *testing.T) {
type NotRed (line 15063) | type NotRed struct
method Validate (line 15067) | func (r *NotRed) Validate() error {
method IsNotRed (line 15075) | func (r NotRed) IsNotRed() bool {
method DoNothing (line 15079) | func (r NotRed) DoNothing() {}
method String (line 15081) | func (r NotRed) String() string { return "not red instance" }
function TestValidateFn (line 15083) | func TestValidateFn(t *testing.T) {
function TestMapStructBasicValidation (line 15206) | func TestMapStructBasicValidation(t *testing.T) {
function TestMapStructPointerValidation (line 15223) | func TestMapStructPointerValidation(t *testing.T) {
function TestMapStructWithKeyValidationOnly (line 15240) | func TestMapStructWithKeyValidationOnly(t *testing.T) {
function TestMapStructWithKeyAndValueValidation (line 15257) | func TestMapStructWithKeyAndValueValidation(t *testing.T) {
function TestMapPointerStructWithNilValue (line 15275) | func TestMapPointerStructWithNilValue(t *testing.T) {
function TestThreeLevelNestedStructs (line 15292) | func TestThreeLevelNestedStructs(t *testing.T) {
function TestMapStructFallbackWithKeysOnly (line 15334) | func TestMapStructFallbackWithKeysOnly(t *testing.T) {
function TestMapPointerStructFallback (line 15360) | func TestMapPointerStructFallback(t *testing.T) {
function TestMapNonStructValueSkipsFallback (line 15386) | func TestMapNonStructValueSkipsFallback(t *testing.T) {
function TestMapSliceValueNoFallback (line 15404) | func TestMapSliceValueNoFallback(t *testing.T) {
function TestMapEmptyStructValueNoError (line 15421) | func TestMapEmptyStructValueNoError(t *testing.T) {
function TestMapNestedEmptyStructs (line 15441) | func TestMapNestedEmptyStructs(t *testing.T) {
function TestMapEmptyValueMap (line 15468) | func TestMapEmptyValueMap(t *testing.T) {
function TestMapEmptyPointerStructValueNoError (line 15485) | func TestMapEmptyPointerStructValueNoError(t *testing.T) {
function TestOmitZeroWithSlices (line 15504) | func TestOmitZeroWithSlices(t *testing.T) {
function TestOmitZeroWithMaps (line 15564) | func TestOmitZeroWithMaps(t *testing.T) {
function TestRequiredIfWithNilBytesSlice (line 15624) | func TestRequiredIfWithNilBytesSlice(t *testing.T) {
function TestRequiredIfWithMaps (line 15699) | func TestRequiredIfWithMaps(t *testing.T) {
function TestRequiredIfWithArrays (line 15774) | func TestRequiredIfWithArrays(t *testing.T) {
type ValuerTypeWithPointerReceiver (line 15845) | type ValuerTypeWithPointerReceiver struct
method ValidatorValue (line 15849) | func (t *ValuerTypeWithPointerReceiver[T]) ValidatorValue() any {
type ValuerTypeWithValueReceiver (line 15853) | type ValuerTypeWithValueReceiver struct
method ValidatorValue (line 15857) | func (t ValuerTypeWithValueReceiver[T]) ValidatorValue() any {
function TestValuerInterface (line 15861) | func TestValuerInterface(t *testing.T) {
Condensed preview — 94 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,397K chars).
[
{
"path": ".github/CODEOWNERS",
"chars": 38,
"preview": "* @go-playground/validator-maintainers"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 539,
"preview": "# Contribution Guidelines\n\n## Quality Standard\n\nTo ensure the continued stability of this package, tests are required th"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.yml",
"chars": 766,
"preview": "name: Bug Report\ndescription: File a bug report\ntitle: \"[Bug]: \"\nlabels: [\"bug\"]\nbody:\n - type: markdown\n attributes"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 206,
"preview": "## Fixes Or Enhances\n\n\n**Make sure that you've checked the boxes below before you submit PR:**\n- [ ] Tests exist or have"
},
{
"path": ".github/dependabot.yml",
"chars": 261,
"preview": "version: 2\nupdates:\n# Maintain dependencies for Golang\n- package-ecosystem: gomod\n directory: \"/\"\n schedule:\n inter"
},
{
"path": ".github/workflows/workflow.yml",
"chars": 1021,
"preview": "on:\n push:\n branches:\n - master\n pull_request:\nname: Test\njobs:\n test:\n strategy:\n matrix:\n go"
},
{
"path": ".gitignore",
"chars": 333,
"preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\nbin\n\n# Architecture"
},
{
"path": ".golangci.yaml",
"chars": 832,
"preview": "version: \"2\"\nlinters:\n default: all\n disable:\n - noinlineerr\n - wsl_v5\n - copyloopvar\n - cyclop\n - depg"
},
{
"path": "LICENSE",
"chars": 1077,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2015 Dean Karn\n\nPermission is hereby granted, free of charge, to any person obtaini"
},
{
"path": "MAINTAINERS.md",
"chars": 450,
"preview": "## Maintainers Guide\n\n### Semantic Versioning\nSemantic versioning as defined [here](https://semver.org) must be strictly"
},
{
"path": "Makefile",
"chars": 399,
"preview": "GOCMD=go\n\nlinters-install:\n\t@golangci-lint --version >/dev/null 2>&1 || { \\\n\t\techo \"installing linting tools...\"; \\\n\t\tcu"
},
{
"path": "README.md",
"chars": 22332,
"preview": "Package validator\n=================\n<img align=\"right\" src=\"logo.png\">[\n\n// MyStruct ..\ntype MyStruct struct {\n\tStrin"
},
{
"path": "_examples/dive/main.go",
"chars": 768,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-playground/validator/v10\"\n)\n\n// Test ...\ntype Test struct {\n\tArray []stri"
},
{
"path": "_examples/gin-upgrading-overriding/main.go",
"chars": 140,
"preview": "package main\n\nimport \"github.com/gin-gonic/gin/binding\"\n\nfunc main() {\n\n\tbinding.Validator = new(defaultValidator)\n\n\t// "
},
{
"path": "_examples/gin-upgrading-overriding/v8_to_v9.go",
"chars": 932,
"preview": "package main\n\nimport (\n\t\"reflect\"\n\t\"sync\"\n\n\t\"github.com/gin-gonic/gin/binding\"\n\t\"github.com/go-playground/validator/v10\""
},
{
"path": "_examples/http-transalations/main.go",
"chars": 2298,
"preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/go-playground/locales/en\"\n\t\"githu"
},
{
"path": "_examples/map-validation/main.go",
"chars": 2248,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/go-playground/validator/v10\"\n)\n\nvar validate *validator.Validate\n\nfunc main()"
},
{
"path": "_examples/simple/main.go",
"chars": 2687,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/go-playground/validator/v10\"\n)\n\n// User contains user information\n"
},
{
"path": "_examples/struct-level/main.go",
"chars": 5379,
"preview": "package main\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/go-playground/validator/v10"
},
{
"path": "_examples/struct-map-rules-validation/main.go",
"chars": 1802,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"github.com/go-playground/validator/v10\"\n)\n\ntype Data struct {\n\tName string\n\tEmail s"
},
{
"path": "_examples/translations/main.go",
"chars": 3204,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/go-playground/locales/en\"\n\tut \"github.com/go-playground/universal-translator"
},
{
"path": "_examples/validate_fn/enum_enumer.go",
"chars": 1936,
"preview": "// Code generated by \"enumer -type=Enum\"; DO NOT EDIT.\n\npackage main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\nconst _EnumName = \"Z"
},
{
"path": "_examples/validate_fn/go.mod",
"chars": 608,
"preview": "module github.com/peczenyj/validator/_examples/validate_fn\n\ngo 1.23.0\n\ntoolchain go1.24.4\n\nreplace github.com/go-playgro"
},
{
"path": "_examples/validate_fn/go.sum",
"chars": 2563,
"preview": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/gabriel-vasile/mimetype v1."
},
{
"path": "_examples/validate_fn/main.go",
"chars": 787,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/go-playground/validator/v10\"\n)\n\n//go:generate enumer -type=Enum\nty"
},
{
"path": "_examples/valuer/main.go",
"chars": 1230,
"preview": "package main\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\n\t\"github.com/go-playground/validator/v10\"\n)\n\n// Nullable wraps a generic value."
},
{
"path": "baked_in.go",
"chars": 97066,
"preview": "package validator\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"cmp\"\n\t\"context\"\n\t\"crypto/sha256\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"erro"
},
{
"path": "benchmarks_test.go",
"chars": 21186,
"preview": "package validator\n\nimport (\n\t\"bytes\"\n\tsql \"database/sql/driver\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc BenchmarkFieldSucce"
},
{
"path": "cache.go",
"chars": 8425,
"preview": "package validator\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\ntype tagType uint8\n\nconst (\n\ttypeDefa"
},
{
"path": "country_codes.go",
"chars": 76160,
"preview": "package validator\n\nvar iso3166_1_alpha2 = map[string]struct{}{\n\t// see: https://www.iso.org/iso-3166-country-codes.html\n"
},
{
"path": "currency_codes.go",
"chars": 3714,
"preview": "package validator\n\nvar iso4217 = map[string]struct{}{\n\t\"AFN\": {}, \"EUR\": {}, \"ALL\": {}, \"DZD\": {}, \"USD\": {},\n\t\"AOA\": {}"
},
{
"path": "doc.go",
"chars": 42682,
"preview": "/*\nPackage validator implements value validations for structs and individual fields\nbased on tags.\n\nIt can also handle C"
},
{
"path": "errors.go",
"chars": 7562,
"preview": "package validator\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\tut \"github.com/go-playground/universal-translator\"\n)"
},
{
"path": "field_level.go",
"chars": 4924,
"preview": "package validator\n\nimport \"reflect\"\n\n// FieldLevel contains all the information and helper functions\n// to validate a fi"
},
{
"path": "go.mod",
"chars": 390,
"preview": "module github.com/go-playground/validator/v10\n\ngo 1.25.0\n\nrequire (\n\tgithub.com/gabriel-vasile/mimetype v1.4.13\n\tgithub."
},
{
"path": "go.sum",
"chars": 2080,
"preview": "github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.m"
},
{
"path": "non-standard/validators/notblank.go",
"chars": 713,
"preview": "package validators\n\nimport (\n\t\"reflect\"\n\t\"strings\"\n\n\t\"github.com/go-playground/validator/v10\"\n)\n\n// NotBlank is the vali"
},
{
"path": "non-standard/validators/notblank_test.go",
"chars": 1248,
"preview": "package validators\n\nimport (\n\t\"testing\"\n\n\t\"github.com/go-playground/assert/v2\"\n\t\"github.com/go-playground/validator/v10\""
},
{
"path": "options.go",
"chars": 1011,
"preview": "package validator\n\n// Option represents a configurations option to be applied to validator during initialization.\ntype O"
},
{
"path": "postcode_regexes.go",
"chars": 4334,
"preview": "package validator\n\nimport (\n\t\"regexp\"\n\t\"sync\"\n)\n\nvar postCodePatternDict = map[string]string{\n\t\"GB\": `^GIR[ ]?0AA|((AB|A"
},
{
"path": "regexes.go",
"chars": 14514,
"preview": "package validator\n\nimport (\n\t\"regexp\"\n\t\"sync\"\n)\n\nconst (\n\talphaRegexString = \"^[a-zA-Z]+$\"\n\talphaSpaceRe"
},
{
"path": "struct_level.go",
"chars": 5466,
"preview": "package validator\n\nimport (\n\t\"context\"\n\t\"reflect\"\n)\n\n// StructLevelFunc accepts all values needed for struct level valid"
},
{
"path": "testdata/a.go",
"chars": 17,
"preview": "package testdata\n"
},
{
"path": "translations/ar/ar.go",
"chars": 36149,
"preview": "package ar\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\tut \"github.com/go-playground/universal-tra"
},
{
"path": "translations/ar/ar_test.go",
"chars": 22966,
"preview": "package ar\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tenglish \"github.com/go-playground/loca"
},
{
"path": "translations/de/de.go",
"chars": 36429,
"preview": "package de\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/de/de_test.go",
"chars": 25600,
"preview": "package de\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tgerman \"github.com/go-playground/local"
},
{
"path": "translations/en/en.go",
"chars": 37379,
"preview": "package en\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/en/en_test.go",
"chars": 26733,
"preview": "package en\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tenglish \"github.com/go-playground/loca"
},
{
"path": "translations/es/es.go",
"chars": 32790,
"preview": "package es\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/es/es_test.go",
"chars": 20430,
"preview": "package es\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tspanish \"github.com/go-playground/loca"
},
{
"path": "translations/fa/fa.go",
"chars": 33733,
"preview": "package fa\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/fa/fa_test.go",
"chars": 20982,
"preview": "package fa\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tenglish \"github.com/go-playground/loca"
},
{
"path": "translations/fr/fr.go",
"chars": 32842,
"preview": "package fr\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/fr/fr_test.go",
"chars": 19168,
"preview": "package fr\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tfrench \"github.com/go-playground/local"
},
{
"path": "translations/id/id.go",
"chars": 38914,
"preview": "package id\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/id/id_test.go",
"chars": 45669,
"preview": "package id\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tindonesia \"github.com/go-playground/lo"
},
{
"path": "translations/it/it.go",
"chars": 30684,
"preview": "package it\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/it/it_test.go",
"chars": 23084,
"preview": "package it\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\titalian \"github.com/go-playground/loca"
},
{
"path": "translations/ja/ja.go",
"chars": 34331,
"preview": "package ja\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/ja/ja_test.go",
"chars": 20467,
"preview": "package ja\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tja_locale \"github.com/go-playground/lo"
},
{
"path": "translations/ko/ko.go",
"chars": 34491,
"preview": "package ko\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/ko/ko_test.go",
"chars": 24857,
"preview": "package ko\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tko_locale \"github.com/go-playground/lo"
},
{
"path": "translations/lv/lv.go",
"chars": 34075,
"preview": "package lv\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/lv/lv_test.go",
"chars": 21518,
"preview": "package lv\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tenglish \"github.com/go-playground/loca"
},
{
"path": "translations/nl/nl.go",
"chars": 32414,
"preview": "package nl\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/nl/nl_test.go",
"chars": 18862,
"preview": "package nl\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tenglish \"github.com/go-playground/loca"
},
{
"path": "translations/pl/pl.go",
"chars": 29773,
"preview": "package pl\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/pl/pl_test.go",
"chars": 27597,
"preview": "package pl\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tpolish \"github.com/go-playground/local"
},
{
"path": "translations/pt/pt.go",
"chars": 33095,
"preview": "package pt\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/pt/pt_test.go",
"chars": 20693,
"preview": "package pt\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\t\"github.com/go-playground/locales/pt\"\n"
},
{
"path": "translations/pt_BR/pt_BR.go",
"chars": 32449,
"preview": "package pt_BR\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut "
},
{
"path": "translations/pt_BR/pt_BR_test.go",
"chars": 19121,
"preview": "package pt_BR\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tbrazilian_portuguese \"github.com/go"
},
{
"path": "translations/ru/ru.go",
"chars": 35863,
"preview": "package ru\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/ru/ru_test.go",
"chars": 24422,
"preview": "package ru\n\nimport (\n\t\"log\"\n\t//\"github.com/rustery/validator\"\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2"
},
{
"path": "translations/th/th.go",
"chars": 32137,
"preview": "package th\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/th/th_test.go",
"chars": 20483,
"preview": "package th\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tthai \"github.com/go-playground/locales"
},
{
"path": "translations/tr/tr.go",
"chars": 32598,
"preview": "package tr\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/tr/tr_test.go",
"chars": 20425,
"preview": "package tr\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tturkish \"github.com/go-playground/loca"
},
{
"path": "translations/uk/uk.go",
"chars": 28761,
"preview": "package uk\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/uk/uk_test.go",
"chars": 31261,
"preview": "package uk\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tukrainian \"github.com/go-playground/lo"
},
{
"path": "translations/vi/vi.go",
"chars": 33660,
"preview": "package vi\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/vi/vi_test.go",
"chars": 20860,
"preview": "package vi\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tvietnamese \"github.com/go-playground/l"
},
{
"path": "translations/zh/zh.go",
"chars": 32525,
"preview": "package zh\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut \"gi"
},
{
"path": "translations/zh/zh_test.go",
"chars": 21315,
"preview": "package zh\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tzhongwen \"github.com/go-playground/loc"
},
{
"path": "translations/zh_tw/zh_tw.go",
"chars": 31013,
"preview": "package zh_tw\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/go-playground/locales\"\n\tut "
},
{
"path": "translations/zh_tw/zh_tw_test.go",
"chars": 19513,
"preview": "package zh_tw\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t. \"github.com/go-playground/assert/v2\"\n\tzhongwen \"github.com/go-playground/"
},
{
"path": "translations.go",
"chars": 425,
"preview": "package validator\n\nimport ut \"github.com/go-playground/universal-translator\"\n\n// TranslationFunc is the function type us"
},
{
"path": "util.go",
"chars": 8190,
"preview": "package validator\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Valuer is an interface that "
},
{
"path": "validator.go",
"chars": 13308,
"preview": "package validator\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"unsafe\"\n)\n\n// per validate construct\ntype validate"
},
{
"path": "validator_instance.go",
"chars": 26904,
"preview": "package validator\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\n\tut \"github.com/go-playgr"
},
{
"path": "validator_test.go",
"chars": 435100,
"preview": "package validator\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"database/sql\"\n\t\"database/sql/driver\"\n\t\"encoding/base64\"\n\t\"encoding/jso"
}
]
About this extraction
This page contains the full source code of the go-playground/validator GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 94 files (2.0 MB), approximately 641.0k tokens, and a symbol index with 995 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.