Introduces Field, Rule, ValidateAll, ResetFields, and AddError for declarative input validation. Includes built-in rules (Required, MinLen, MaxLen, Min, Max, Email, Pattern, Custom) and a signup example exercising the full API surface.
129 lines
2.7 KiB
Go
129 lines
2.7 KiB
Go
package via
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Rule defines a single validation check for a Field.
|
|
type Rule struct {
|
|
validate func(val string) error
|
|
}
|
|
|
|
// Required rejects empty or whitespace-only values.
|
|
func Required(msg ...string) Rule {
|
|
m := "This field is required"
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
return Rule{func(val string) error {
|
|
if strings.TrimSpace(val) == "" {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
// MinLen rejects values shorter than n characters.
|
|
func MinLen(n int, msg ...string) Rule {
|
|
m := fmt.Sprintf("Must be at least %d characters", n)
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
return Rule{func(val string) error {
|
|
if len(val) < n {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
// MaxLen rejects values longer than n characters.
|
|
func MaxLen(n int, msg ...string) Rule {
|
|
m := fmt.Sprintf("Must be at most %d characters", n)
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
return Rule{func(val string) error {
|
|
if len(val) > n {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
// Min parses the value as an integer and rejects values less than n.
|
|
func Min(n int, msg ...string) Rule {
|
|
m := fmt.Sprintf("Must be at least %d", n)
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
return Rule{func(val string) error {
|
|
v, err := strconv.Atoi(val)
|
|
if err != nil {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
if v < n {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
// Max parses the value as an integer and rejects values greater than n.
|
|
func Max(n int, msg ...string) Rule {
|
|
m := fmt.Sprintf("Must be at most %d", n)
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
return Rule{func(val string) error {
|
|
v, err := strconv.Atoi(val)
|
|
if err != nil {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
if v > n {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
// Pattern rejects values that don't match the regular expression re.
|
|
func Pattern(re string, msg ...string) Rule {
|
|
m := "Invalid format"
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
compiled := regexp.MustCompile(re)
|
|
return Rule{func(val string) error {
|
|
if !compiled.MatchString(val) {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
var emailRegexp = regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
|
|
|
|
// Email rejects values that don't look like an email address.
|
|
func Email(msg ...string) Rule {
|
|
m := "Invalid email address"
|
|
if len(msg) > 0 {
|
|
m = msg[0]
|
|
}
|
|
return Rule{func(val string) error {
|
|
if !emailRegexp.MatchString(val) {
|
|
return fmt.Errorf("%s", m)
|
|
}
|
|
return nil
|
|
}}
|
|
}
|
|
|
|
// Custom creates a rule from a user-provided validation function.
|
|
// The function should return nil for valid input and an error for invalid input.
|
|
func Custom(fn func(string) error) Rule {
|
|
return Rule{validate: fn}
|
|
}
|