Rules from tags¶
b.Tags("validate") configures the rules of the tags of the fields of the struct and of its nested structs in the syntax of go-playground/validator: validate:"required,max=64". It is for a migration: the structs keep their tags, and the rules move to code one by one — the tags and the rules in code are mixed in one Configure.
The rules of the tags are the rules of valigo: the same messages in the languages of the users, the codes, the JSON Schema and the speed — a valid object is validated without allocations, see Performance.
Example¶
package main
import (
"context"
"fmt"
"github.com/insei/valigo"
"github.com/insei/valigo/rules/str"
)
type Address struct {
City string `validate:"required,max=32"`
}
type SignUp struct {
Email string `validate:"required,email"`
Password string `validate:"required,min=8"`
Confirm string `validate:"eqfield=Password"`
Age int `validate:"omitempty,gte=18,lte=120"`
Tags []string `validate:"max=3,dive,required,max=16"`
Address *Address // the rules of City apply when the address is present
Nick string
}
func main() {
v := valigo.New()
valigo.Configure[SignUp](v, func(b valigo.Configurator[SignUp], s *SignUp) {
b.Tags("validate")
// the rules in code with the tags
b.Field(&s.Nick).As(str.Of).Trim().Alphanumeric()
})
errs := v.ValidateTyped(context.Background(), &SignUp{
Email: "ann", Password: "secret", Confirm: "secrets", Age: 16, Tags: []string{"go", ""}, Nick: " a b ",
})
for _, err := range errs {
fmt.Println(err.Location, "-", err.Message, "-", err.Code)
}
}
Output:
Email - Should be email address - string.email
Password - Cannot be shorter than 8 characters - string.min_runes
Confirm - Should be equal to Password - string.equal_field
Age - Cannot be less than 18 - number.min
Tags[1] - Should be fulfilled - string.required
Nick - Should contain only letters and digits - string.alphanumeric
Rules¶
| Fields | Tags of go-playground/validator | Rules of valigo |
|---|---|---|
| all | required |
Required: a string is not empty, a number is not zero, a bool is true, a slice and a map have elements, a pointer is not nil |
| all | omitempty, omitnil |
the next rules are skipped for the zero value; a nil pointer is absent anyway |
| all | required_if=F v, required_unless=F v, required_with=F G, required_with_all, required_without, required_without_all |
Required under the condition of the fields F, G of the same struct: their values, or their values are not zero |
| all | a\|b |
Or: one of the alternatives passes, the errors of the first one when none does |
| strings | min, max, len, gt, gte, lt, lte |
MinRunes, MaxRunes: the lengths in characters |
| strings | eq, ne, oneof=a b, eq_ignore_case |
AnyOf, eq.NotEqual, AnyOf, EqualFold |
| strings | contains, excludes, startswith, endswith, startsnotwith, endsnotwith, containsany, excludesall |
Contains, Excludes, Prefix, Suffix, NotPrefix, NotSuffix, ContainsAny, ExcludesAny |
| strings | alpha, alphanum, number, numeric, hexadecimal, ascii, lowercase, uppercase |
Alpha, Alphanumeric, Digits, Numeric, Hexadecimal, ASCII, Lowercase, Uppercase |
| strings | email, url, http_url, uuid, ip, ipv4, ipv6, cidr, mac, hostname, hostname_rfc1123, e164 |
Email, URL, URL, UUID, IP, IPv4, IPv6, CIDR, MAC, Hostname, Hostname, E164 |
| strings | base64, base64url, json, semver, hexcolor, datetime=2006-01-02, iso3166_1_alpha2, iso4217, credit_card, luhn_checksum |
Base64, Base64URL, JSON, Semver, HexColor, Datetime, CountryCode, CurrencyCode, CreditCard, Luhn |
| strings | eqfield, nefield |
EqualField, NotEqualField |
| numbers | min, gte, max, lte, gt, lt, eq, ne, oneof=1 2 |
Min, Max, GreaterThan, LessThan, AnyOf, eq.NotEqual, AnyOf |
| numbers | gtefield, ltefield, gtfield, ltfield, eqfield, nefield |
MinField, MaxField, GreaterField, LessField, eq.EqualField, eq.NotEqualField |
| numbers | latitude, longitude |
Latitude, Longitude |
bool |
eq=true, ne=true |
eq.Equal, eq.NotEqual |
time.Time |
gt, gte, lt, lte without a parameter, gtfield, ltfield |
InFuture, InPast, AfterField, BeforeField |
| slices, maps | min, max, len, gt, gte, lt, lte, eq |
the rules of the length |
| slices | unique |
eq.Slice(...).Unique() of the elements of comparable types |
| slices | dive |
the next rules are the rules of the elements; the elements of struct types are validated by the tags of their type, Items[1].Title, dive,required checks nil elements of []*T |
| maps | dive, dive,keys,...,endkeys,... |
the rules of the values and of the keys of map[string]V |
| pointers to nested structs | required |
the fields of a nested struct have their own tags |
Pointers to the values have the rules of the values, a nil pointer is absent. The rules on fields and the conditions take the names of the fields of the same struct, or their nested fields Inner.Field. 0x2C in a parameter is a comma, 0x7C is a pipe, like in go-playground/validator.
Not supported¶
These tags panic in Configure: a typo or an unsupported rule doesn't turn into a missing check. Write their rules in code.
| Tags | In code |
|---|---|
excluded_if, excluded_unless, excluded_with, excluded_with_all, excluded_without, excluded_without_all |
b.When(cond).Field(&m.X).Custom(...) that fails on a present value |
eqcsfield, necsfield, gtcsfield, gtecsfield, ltcsfield, ltecsfield, fieldcontains, fieldexcludes |
the rules on other fields with the pointers to any field of the model, EqualField(&m.Other.Field), or b.Custom |
alphaunicode, alphanumunicode, boolean, containsrune, excludesrune, multibyte, printascii, ne_ignore_case, oneofci |
Custom or Regexp |
uuid3, uuid4, uuid5, uuid_rfc4122... , ulid, cve |
UUID with Custom of the version, Regexp |
uri, urn_rfc2141, url_encoded, datauri, fqdn, hostname_port, tcp_addr, udp_addr, unix_addr, ip_addr... , cidrv4, cidrv6 |
URL, Hostname, IP, CIDR with Custom, or Custom with the parsers of the standard library |
isbn, issn, bic, ssn, jwt, html, html_encoded, rgb, rgba, hsl, hsla, iscolor, md5, sha256..., btc_addr, eth_addr, mongodb, cron, timezone, bcp47_language_tag, iso3166_1_alpha3, iso3166_1_alpha_numeric, iso3166_2, iso4217_numeric, postcode_iso3166_alpha2 |
Custom or Regexp |
dir, dirpath, file, filepath, image |
Custom: valigo doesn't touch the file system |
isdefault, omitzero, structonly, nostructlevel, skip_unless |
When and Custom |
dive into the elements of slices of slices, of maps with other keys than strings, of maps of pointers and structs; unique of the slices of pointers and structs, unique=Field |
Each, EachKey, EachValue and Custom in code |
the custom tags of RegisterValidation, the aliases of RegisterAlias |
the rules of the type in code, see Your types |
Differences from go-playground/validator¶
requiredisRequiredof valigo: a string is not empty, a number is not zero, a slice and a map have elements — go-playground/validator accepts an empty non-nil slice and map, and a pointer to an empty string.- The fields of a nil nested struct are skipped, like by go-playground/validator. The rules in code check
Requiredof these fields, see Absent values. - The messages are the messages of valigo in the languages of the users, the errors have the codes of valigo; the alternatives
a|breport the errors of the first one. - The formats are the formats of valigo, see Strings:
email,urlandhostnamecan differ from go-playground/validator in details. gt,ltoftime.Timecompare with the current time without a parameter, like go-playground/validator, and fail on a parameter.- The rules of the tags after
omitemptyand the conditional ones aren't in the JSON Schema: they don't apply to every value. - A valid object is validated without allocations, also with
diveinto the elements of structs; the alternatives allocate the errors of the failed ones.