Skip to content

Instantly share code, notes, and snippets.

@joshbedo
Created December 31, 2025 22:49
Show Gist options
  • Select an option

  • Save joshbedo/39a60ac929dd76fd216d612a39c56a3a to your computer and use it in GitHub Desktop.

Select an option

Save joshbedo/39a60ac929dd76fd216d612a39c56a3a to your computer and use it in GitHub Desktop.
Validate structs using reflections
// You can edit this code!
// Click here and start typing.
package main
import (
"fmt"
"reflect"
"strconv"
"strings"
)
type User struct {
Name string `validate:"min=2,max=12"`
Email string `validate:"required,email"`
}
func validateMinLength(
rule string,
field reflect.Value,
fieldName string,
) error {
//fmt.Println(rule, field, fieldName)
min, _ := strconv.Atoi(
strings.TrimPrefix(rule, "min="),
)
if len(field.String()) < min {
return fmt.Errorf(
"%s must be at least %d characters long",
fieldName,
min,
)
}
return nil
}
func validateMaxLength(
rule string,
field reflect.Value,
fieldName string,
) error {
fmt.Println(rule, field, fieldName)
return nil
}
func applyRule(
rule string,
field reflect.Value,
fieldName string,
) error {
switch {
case strings.HasPrefix(rule, "min="):
return validateMinLength(rule, field, fieldName)
case strings.HasPrefix(rule, "max="):
return validateMaxLength(rule, field, fieldName)
// case strings.HasPrefix(rule, "max="):
// max, _ := strconv.Atoi(
// strings.TrimPrefix(rule, "max="),
// )
// if len(field.String()) > max {
// return fmt.Errorf(
// "%s must be less than %d characters long",
// fieldName,
// max,
// )
// }
// case rule == "required":
// if field.String() == "" {
// return fmt.Errorf(
// "%s is required",
// fieldName,
// )
// }
// case rule == "email":
// _, err := mail.ParseAddress(field.String())
// if err != nil {
// return fmt.Errorf(
// "%s must be a valid email address",
// fieldName,
// )
}
return nil
}
func validate(val interface{}) error {
v := reflect.ValueOf(val)
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
tag := v.Type().Field(i).Tag.Get("validate")
fieldName := v.Type().Field(i).Name
if tag == "" {
continue
}
rules := strings.Split(tag, ",")
for _, rule := range rules {
if err := applyRule(rule, field, fieldName); err != nil {
return err
}
}
}
return nil
}
func main() {
user := User{
Name: "Josh",
Email: "josh@gmail.com",
}
fmt.Println(validate(user))
invalidUser := User{
Name: "a",
Email: "joshm",
}
fmt.Println(validate(invalidUser))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment