package zvalidate
import "zgo.at/zvalidate"
Package zvalidate provides simple validation for Go.
See the README.md for an introduction.
Code:play
Output:Example¶
package main
import (
"fmt"
"zgo.at/zvalidate"
)
func main() {
email := "martin@arp42.net"
v := zvalidate.New()
v.Required("email", email)
m := v.Email("email", email)
if v.HasErrors() {
fmt.Printf("Had the following validation errors:\n%s", v)
}
fmt.Printf("parsed email: %s\n", m.Address)
}
parsed email: martin@arp42.net
Index ¶
- Variables
- func TemplateError(k string, v *Validator) template.HTML
- func TemplateHasErrors(v *Validator) bool
- type Messages
- type Validator
- func As(err error) *Validator
- func New() Validator
- func (v *Validator) Append(key, value string, format ...any)
- func (v *Validator) Boolean(key, value string, message ...string) bool
- func (v Validator) Code() int
- func (v *Validator) Contains(key, value string, ranges []*unicode.RangeTable, runes []rune, message ...string)
- func (v *Validator) Date(key, value, layout string, message ...string) time.Time
- func (v *Validator) Domain(key, value string, message ...string) []string
- func (v *Validator) Email(key, value string, message ...string) mail.Address
- func (v Validator) Error() string
- func (v Validator) ErrorJSON() ([]byte, error)
- func (v *Validator) ErrorOrNil() error
- func (v *Validator) Exclude(key, value string, exclude []string, message ...string) string
- func (v *Validator) HTML() template.HTML
- func (v *Validator) HasErrors() bool
- func (v *Validator) Hex(key, value string, message ...string) int64
- func (v *Validator) HexColor(key, value string, message ...string) (uint8, uint8, uint8)
- func (v *Validator) Hostname(key, value string, message ...string) []string
- func (v *Validator) IP(key, value string, message ...string) net.IP
- func (v *Validator) IPv4(key, value string, message ...string) net.IP
- func (v *Validator) Include(key string, value, include any, message ...string) any
- func (v *Validator) Integer(key, value string, message ...string) int64
- func (v *Validator) Len(key, value string, min, max int, message ...string) int
- func (v *Validator) Merge(other Validator)
- func (v *Validator) Messages(m Messages)
- func (v *Validator) Octal(key, value string, message ...string) int64
- func (v *Validator) Phone(key, value string, message ...string) string
- func (v *Validator) PhoneInternational(key, value string, message ...string) string
- func (v *Validator) Pop(key string) []string
- func (v *Validator) Range(key string, value, min, max int64, message ...string)
- func (v *Validator) Required(key string, value any, message ...string)
- func (v *Validator) String() string
- func (v *Validator) Sub(key, subKey string, err error)
- func (v *Validator) URL(key, value string, message ...string) *url.URL
- func (v *Validator) URLLocal(key, value string, message ...string) *url.URL
- func (v *Validator) UTF8(key, value string, message ...string)
Examples ¶
Variables ¶
var ( AlphaNumeric = &unicode.RangeTable{ R16: []unicode.Range16{{0x0030, 0x0039, 1}, {0x0041, 0x005a, 1}, {0x0061, 0x007a, 1}}, LatinOffset: 3, } ASCII = &unicode.RangeTable{ R16: []unicode.Range16{{0x0020, 0x007e, 1}}, LatinOffset: 1, } )
Range tables for Contains()
TODO: move to zstd/zunicode?
var DefaultMessages = Messages{ Required: func() string { return "must be set" }, Domain: func() string { return "must be a valid domain" }, Hostname: func() string { return "must be a valid hostname" }, URL: func() string { return "must be a valid url" }, Email: func() string { return "must be a valid email address" }, IPv4: func() string { return "must be a valid IPv4 address" }, IP: func() string { return "must be a valid IPv4 or IPv6 address" }, HexColor: func() string { return "must be a valid color code" }, LenLonger: func() string { return "must be longer than %d characters" }, LenShorter: func() string { return "must be shorter than %d characters" }, Exclude: func() string { return "cannot be ‘%s’" }, Include: func() string { return "must be one of ‘%s’" }, Integer: func() string { return "must be a whole number" }, Hex: func() string { return "must be a whole number in base 16 (hexadecimal)" }, Octal: func() string { return "must be a whole number in base 8 (octal)" }, Bool: func() string { return "must be a boolean" }, Date: func() string { return "must be a date as ‘%s’" }, Phone: func() string { return "must be a valid phone number" }, PhoneInternational: func() string { return "must be a valid phone number with country dialing prefix" }, RangeHigher: func() string { return "must be %d or higher" }, RangeLower: func() string { return "must be %d or lower" }, UTF8: func() string { return "must be UTF-8" }, Contains: func() string { return "cannot contain the characters %s" }, }
Functions ¶
func TemplateError ¶
TemplateError displays validation errors for the given key.
This will Pop() errors and modify the Validator in-place, so we can see if
there are any "hidden" errors later on.
Code:play
Output:Example¶
package main
import (
"html/template"
"os"
"zgo.at/zvalidate"
)
func main() {
funcs := template.FuncMap{
"validate": zvalidate.TemplateError,
"has_errors": zvalidate.TemplateHasErrors,
}
t := template.Must(template.New("").Funcs(funcs).Parse(`
<input name="xxx">
{{validate "xxx" .Validate}}
{{if has_errors .Validate}}Hidden: {{.Validate.HTML}}{{end}}
`))
v := zvalidate.New()
v.Append("xxx", "oh noes")
v.Append("hidden", "sneaky")
t.Execute(os.Stdout, map[string]any{
"Validate": &v,
})
}
<input name="xxx">
<span class="err">Error: oh noes</span>
Hidden: <ul class='zvalidate'>
<li><strong>hidden</strong>: sneaky.</li>
</ul>
func TemplateHasErrors ¶
TemplateHasErrors reports if there are any validation errors.
This is useful because "and" evaluates all arguments, and this will error out:
{{if and .Validate .Validate.HasErrors}}
Types ¶
type Messages ¶
type Messages struct { Required func() string Domain func() string Hostname func() string URL func() string Email func() string IPv4 func() string IP func() string HexColor func() string LenLonger func() string LenShorter func() string Exclude func() string Include func() string Integer func() string Hex func() string Octal func() string Bool func() string Date func() string Phone func() string PhoneInternational func() string RangeHigher func() string RangeLower func() string UTF8 func() string Contains func() string }
type Validator ¶
type Validator struct { Errors map[string][]string `json:"errors"` // contains filtered or unexported fields }
Validator hold the validation errors.
Typically you shouldn't create this directly but use the New() function.
func As ¶
As tries to convert this error to a Validator, returning nil if it's not.
func New ¶
func New() Validator
New initializes a new Validator.
func (*Validator) Append ¶
Append a new error.
func (*Validator) Boolean ¶
Boolean parses as string as a boolean.
func (Validator) Code ¶
Code returns the HTTP status code for the error. Satisfies the guru.coder interface in zgo.at/guru.
func (*Validator) Contains ¶
func (v *Validator) Contains(key, value string, ranges []*unicode.RangeTable, runes []rune, message ...string)
Contains validates that this string only contains the given characters.
This implies the UTF8() validation.
The value is in either the unicode range or runes list. For example:
zvalidate.Contains("key", val, zvalidate.AlphaNumeric, []rune{'_', '-'})
Will allow all ASCII letters and numbers and '_' and '-'.
If you have a lot of values it's faster to create a custom RangeTable.
Useful ranges:
zvalidate.AlphaNumeric a-0A-Za-z zvalidate.ASCII All ASCII characters except control characters. unicode.Letter Any "letter" (in any script) unicode.Number Any "number" (in any script) unicode.ASCII_Hex_Digit 0-9A-Fa-f
func (*Validator) Date ¶
Date parses a string in the given date layout.
func (*Validator) Domain ¶
Domain parses a domain as individual labels.
A domain must consist of at least two labels. So "com" or "localhost" – while technically valid domain names – are not accepted, whereas "example.com" or "me.localhost" are. For the overwhelming majority of applications this makes the most sense.
This works for internationalized domain names (IDN), either as UTF-8 characters or as punycode.
func (*Validator) Email ¶
Email parses an email address.
func (Validator) Error ¶
Error interface.
func (Validator) ErrorJSON ¶
ErrorJSON for reporting errors as JSON.
func (*Validator) ErrorOrNil ¶
ErrorOrNil returns nil if there are no errors, or the Validator object if there are.
This makes it a bit more elegant to return from a function:
if v.HasErrors() { return v } return nil
Can now be:
return v.ErrorOrNil()
func (*Validator) Exclude ¶
Exclude validates that the value is not in the exclude list.
This list is matched case-insensitive and with leading/trailing whitespace ignored. The returned value is the same as the input value.
func (*Validator) HTML ¶
HTML representation of all errors, or a blank string if there are none.
func (*Validator) HasErrors ¶
HasErrors reports if this validation has any errors.
func (*Validator) Hex ¶
Hex parses a string as a base-16 integer.
func (*Validator) HexColor ¶
HexColor parses a color as a hex triplet (e.g. #ffffff or #fff).
func (*Validator) Hostname ¶
Hostname checks if this is a valid hostname.
This is different from Domain in that it considers any hostname valid, whereas Domain() is a bit stricter and validates if this is likely to be a publicly accessible domain. e.g. "localhost" is valid in Hostname(), but not Domain().
func (*Validator) IP ¶
IP parses an IPv4 or IPv6 address.
func (*Validator) IPv4 ¶
IPv4 parses an IPv4 address.
func (*Validator) Include ¶
Include validates that the value is in the include list.
This list is matched case-insensitive and with leading/trailing whitespace ignored. The returned value is the "sanitized" value that matched.
func (*Validator) Integer ¶
Integer parses a string as an integer.
func (*Validator) Len ¶
Len validates the character (rune) length of a string.
A maximum of 0 indicates there is no upper limit.
func (*Validator) Merge ¶
Merge errors from another validator in to this one.
func (*Validator) Messages ¶
Messages sets the messages to use for validation errors.
func (*Validator) Octal ¶
Octal parses a string as a base-8 integer.
func (*Validator) Phone ¶
Phone parses a phone number.
There are a great amount of writing conventions for phone numbers: https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers
This merely checks a field contains 5 to 20 characters "0123456789+\-() .", which is not very strict but should cover all conventions.
Returns the phone number with grouping/spacing characters removed.
func (*Validator) PhoneInternational ¶
PhoneInternational parses a phone number.
This is identical to Phone(), except that a phone must start with a "+", requiring a country prefix (Phone() will deal with country prefixes as well, it just isn't required).
Returns the phone number with grouping/spacing characters removed.
func (*Validator) Pop ¶
Pop an error, removing all errors for this key.
This is mostly useful when displaying errors next to forms: Pop() all the errors you want to display, and then display anything that's left with a flash message or the like. This prevents "hidden" errors.
Returns nil if there are no errors for this key.
func (*Validator) Range ¶
Range sets the minimum and maximum value of a integer.
A maximum of 0 indicates there is no upper limit.
func (*Validator) Required ¶
Required validates that the value is not the type's zero value.
For slices it also checks it's not a slice of zero values.
func (*Validator) String ¶
Strings representation of all errors, or a blank string if there are none.
func (*Validator) Sub ¶
Sub adds sub-validations.
Errors from the subvalidation are merged with the top-level one, the keys are added as "top.sub" or "top[n].sub".
If the error is not a Validator the text will be added as just the key name without subkey (i.e. the same as v.Append("key", "msg")).
For example:
func (c Customer) validateSettings() error { v := zvalidate.New() v.Required("domain", c.Domain) v.Required("email", c.Email) return v.ErrorOrNil() } v := zvalidate.New() v.Required("name", customer.Name) // Keys will be added as "settings.domain" and "settings.email". v.Sub("settings", "", customer.validateSettings()) // List as array; keys will be added as "addresses[0].city" etc. for i, addr := range customer.Addresses { v.Sub("addresses", i, addr.Validate()) }
func (*Validator) URL ¶
URL parses an URL.
The URL may consist of a scheme, host, path, and query parameters. Only the host is required.
Local URLs are not considered valid; the host needs to have at least two labels. Use URLLocal() if you also want to accept e.g "http://localhost".
If the scheme is not given "http" will be prepended.
func (*Validator) URLLocal ¶
URLLocal is like URL, but also considers local URLs to be valid.
func (*Validator) UTF8 ¶
UTF8 validates that this string is valid UTF-8.
Caveat: this will consider NULL bytes *invalid* even though they're valid in UTF-8. Many tools don't accept it (e.g. PostgreSQL and SQLite), there's very rarely a reason to include them in strings, and most uses I've seen is from people trying to insert exploits. So the practical thing to do is just to reject it.
Source Files ¶
messages.go punycode.go template.go utf8.go validators.go zvalidate.go
Directories ¶
Path | Synopsis |
---|---|
internal |
- Version
- v0.0.0-20241009015312-efd45e4f063d (latest)
- Published
- Oct 9, 2024
- Platform
- linux/amd64
- Imports
- 16 packages
- Last checked
- 3 weeks ago –
Tools for package owners.