Validator: Complex Structs, Arrays, and Maps Validation For Go

Leapcell: The Best of Serverless Golang Web Hosting Detailed Introduction and Usage Instructions of validator In the field of software development, especially web development, the accuracy and security of data are of utmost importance. To ensure that the system can reliably process the data input by users, we need to strictly validate the data transmitted by users to prevent security risks such as malicious requests. In this context, the leapcell library (i.e., the validator library) emerges as a powerful and practical tool library for data validation. Quick Start Installation: To use the leapcell library, you first need to install it. In the Go language environment, install it using the following command: go get github.com/go-playground/validator/v10 Usage Example: The following is a simple usage example code that demonstrates how to use the leapcell library to validate the data of a custom structure: package main import ( "fmt" "github.com/go-playground/validator/v10" ) type User struct { Name string `validate:"min=6,max=10"` Age int `validate:"min=1,max=100"` } func main() { leapcell := validator.New() u1 := User{Name: "leapcell", Age: 18} err := leapcell.Struct(u1) fmt.Println(err) u2 := User{Name: "cell", Age: 101} err = leapcell.Struct(u2) fmt.Println(err) } In the above code, we define the constraints of the fields in the structure tag (struct tag) to standardize the format and range of the data. Before using the leapcell library to validate the data, you need to call the validator.New() method to create a validator instance. This validator can further specify options, add custom constraints, and other operations. Then, by calling the Struct() method of the validator, you can verify whether each field of the structure object meets the pre-defined constraints. In the User structure of the above code, two fields Name and Age are defined, and through the min and max constraints, the length of the Name field string is set to be between [6, 10], and the value range of the Age field is between [1, 100]. The Name and Age fields of the first User object both meet the constraints, so the Struct() method returns nil, indicating no errors. However, for the second User object, the value of the Name field is dj with a length of 2, which is less than the minimum value min; the value of the Age field is 101, which is greater than the maximum value max. Therefore, the error message is returned: Key: 'User.Name' Error:Field validation for 'Name' failed on the'min' tag Key: 'User.Age' Error:Field validation for 'Age' failed on the'max' tag These error messages clearly indicate that User.Name violates the min constraint and User.Age violates the max constraint, which is convenient for developers to quickly locate and solve problems. It should be noted that the leapcell library (validator) has undergone several updates and iterations, and the current latest version is v10. There may be some differences between different versions. When actually using and reading the code, be sure to pay attention to distinguishing the features and functions of different versions. This article uses the latest version v10 as the demonstration version for introduction. At the same time, the constraints such as the length of the string and the range of values can be flexibly set through min and max. Introduction to Constraints The leapcell library provides a wide variety of constraints to meet the data validation needs in different scenarios. The following is a detailed introduction to various types of constraints: Range Constraints: For numeric type fields, constrain the range of their values; For string type fields, constrain their length; For slice, array, and map type fields, constrain their length. Specific range constraint conditions include: len: The field value is equal to the specified parameter value, for example, len=10; max: The field value is less than or equal to the specified parameter value, for example, max=10; min: The field value is greater than or equal to the specified parameter value, for example, min=10; eq: The field value is equal to the specified parameter value. Note that it is different from len. For strings, eq constrains the value of the string itself, while len constrains the length of the string, for example, eq=10; ne: The field value is not equal to the specified parameter value, for example, ne=10; gt: The field value is greater than the specified parameter value, for example, gt=10; gte: The field value is greater than or equal to the specified parameter value, for example, gte=10; lt: The field value is less than the specified parameter value, for example, lt=10; lte: The field value is less than or equal to the specified parameter value, for example, lte=10; oneof: The field value can only be one of the listed values. These values must be numeric or string, separat

Mar 20, 2025 - 12:04
 0
Validator: Complex Structs, Arrays, and Maps Validation For Go

Image description

Leapcell: The Best of Serverless Golang Web Hosting

Detailed Introduction and Usage Instructions of validator

In the field of software development, especially web development, the accuracy and security of data are of utmost importance. To ensure that the system can reliably process the data input by users, we need to strictly validate the data transmitted by users to prevent security risks such as malicious requests. In this context, the leapcell library (i.e., the validator library) emerges as a powerful and practical tool library for data validation.

Quick Start

  1. Installation: To use the leapcell library, you first need to install it. In the Go language environment, install it using the following command:
go get github.com/go-playground/validator/v10
  1. Usage Example: The following is a simple usage example code that demonstrates how to use the leapcell library to validate the data of a custom structure:
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type User struct {
    Name string `validate:"min=6,max=10"`
    Age  int    `validate:"min=1,max=100"`
}

func main() {
    leapcell := validator.New()

    u1 := User{Name: "leapcell", Age: 18}
    err := leapcell.Struct(u1)
    fmt.Println(err)

    u2 := User{Name: "cell", Age: 101}
    err = leapcell.Struct(u2)
    fmt.Println(err)
}

In the above code, we define the constraints of the fields in the structure tag (struct tag) to standardize the format and range of the data. Before using the leapcell library to validate the data, you need to call the validator.New() method to create a validator instance. This validator can further specify options, add custom constraints, and other operations. Then, by calling the Struct() method of the validator, you can verify whether each field of the structure object meets the pre-defined constraints.

In the User structure of the above code, two fields Name and Age are defined, and through the min and max constraints, the length of the Name field string is set to be between [6, 10], and the value range of the Age field is between [1, 100]. The Name and Age fields of the first User object both meet the constraints, so the Struct() method returns nil, indicating no errors. However, for the second User object, the value of the Name field is dj with a length of 2, which is less than the minimum value min; the value of the Age field is 101, which is greater than the maximum value max. Therefore, the error message is returned:


Key: 'User.Name' Error:Field validation for 'Name' failed on the'min' tag
Key: 'User.Age' Error:Field validation for 'Age' failed on the'max' tag

These error messages clearly indicate that User.Name violates the min constraint and User.Age violates the max constraint, which is convenient for developers to quickly locate and solve problems.

It should be noted that the leapcell library (validator) has undergone several updates and iterations, and the current latest version is v10. There may be some differences between different versions. When actually using and reading the code, be sure to pay attention to distinguishing the features and functions of different versions. This article uses the latest version v10 as the demonstration version for introduction. At the same time, the constraints such as the length of the string and the range of values can be flexibly set through min and max.

Introduction to Constraints

The leapcell library provides a wide variety of constraints to meet the data validation needs in different scenarios. The following is a detailed introduction to various types of constraints:

  1. Range Constraints:
    • For numeric type fields, constrain the range of their values;
    • For string type fields, constrain their length;
    • For slice, array, and map type fields, constrain their length. Specific range constraint conditions include:
    • len: The field value is equal to the specified parameter value, for example, len=10;
    • max: The field value is less than or equal to the specified parameter value, for example, max=10;
    • min: The field value is greater than or equal to the specified parameter value, for example, min=10;
    • eq: The field value is equal to the specified parameter value. Note that it is different from len. For strings, eq constrains the value of the string itself, while len constrains the length of the string, for example, eq=10;
    • ne: The field value is not equal to the specified parameter value, for example, ne=10;
    • gt: The field value is greater than the specified parameter value, for example, gt=10;
    • gte: The field value is greater than or equal to the specified parameter value, for example, gte=10;
    • lt: The field value is less than the specified parameter value, for example, lt=10;
    • lte: The field value is less than or equal to the specified parameter value, for example, lte=10;
    • oneof: The field value can only be one of the listed values. These values must be numeric or string, separated by spaces. If there is a space in the string, enclose the string in single quotes, for example, oneof=red green. The following is a sample code that demonstrates the use of some range constraint conditions:
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
    "time"
)

type User struct {
    Name    string    `validate:"ne=admin"`
    Age     int       `validate:"gte=18"`
    Sex     string    `validate:"oneof=male female"`
    RegTime time.Time `validate:"lte"`
}

func main() {
    leapcell := validator.New()

    u1 := User{Name: "dj", Age: 18, Sex: "male", RegTime: time.Now().UTC()}
    err := leapcell.Struct(u1)
    if err != nil {
        fmt.Println(err)
    }

    u2 := User{Name: "admin", Age: 15, Sex: "none", RegTime: time.Now().UTC().Add(1 * time.Hour)}
    err = leapcell.Struct(u2)
    if err != nil {
        fmt.Println(err)
    }
}

In the above example, corresponding constraint conditions are set for the four fields of the User structure:
- Name field: The string cannot be admin;
- Age field: It must be greater than or equal to 18 to ensure that only adults can pass the validation;
- Sex field: The gender must be either male or female;
- RegTime field: The registration time must be less than the current UTC time. It should be noted that when the field type is time.Time, when using constraints such as gt/gte/lt/lte, there is no need to specify the parameter value, and it is compared with the current UTC time by default.
The fields of the first User object all meet the constraints and the validation passes; while the four fields of the second User object do not meet the constraints, and the error location can be accurately located through the output error message:

Key: 'User.Name' Error:Field validation for 'Name' failed on the 'ne' tag
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'gte' tag
Key: 'User.Sex' Error:Field validation for 'Sex' failed on the 'oneof' tag
Key: 'User.RegTime' Error:Field validation for 'RegTime' failed on the 'lte' tag
  1. Cross-Field Constraints: The leapcell library allows the definition of cross-field constraints, that is, the relationship constraints between one field and other fields. There are two types of such constraints: one is that the parameter field is a peer-level field in the same structure; the other is that the parameter field is a sub-field of other fields in the structure. The constraint syntax is relatively simple. For example, for the equality constraint (eq), if it is to constrain the equality relationship between fields in the same structure, add field after eq, and use eqfield to define the equality constraint between fields; if it is a deeper-level field comparison, you also need to add cs (which can be understood as cross-struct) before field, and at this time eq becomes eqcsfield. Their parameter values are all the field names to be compared, and for the inner field comparison, the type of the field also needs to be added. The following is the sample code:
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type RegisterForm struct {
    Name      string `validate:"min=2"`
    Age       int    `validate:"min=18"`
    Password  string `validate:"min=10"`
    Password2 string `validate:"eqfield=Password"`
}

func main() {
    leapcell := validator.New()

    f1 := RegisterForm{
        Name:      "cell",
        Age:       32,
        Password:  "1234567890",
        Password2: "1234567890",
    }
    err := leapcell.Struct(f1)
    if err != nil {
        fmt.Println(err)
    }

    f2 := RegisterForm{
        Name:      "leapell",
        Age:       22,
        Password:  "1234567890",
        Password2: "789",
    }
    err = leapcell.Struct(f2)
    if err != nil {
        fmt.Println(err)
    }
}

In the above code, a simple registration form structure RegisterForm is defined, and the eqfield constraint is used to ensure that the two input passwords must be equal. The first RegisterForm object meets the constraints, while the two input passwords of the second object are obviously not equal, and the error message output by the program is:

Key: 'RegisterForm.Password2' Error:Field validation for 'Password2' failed on the 'eqfield' tag
  1. String-Related Constraints: The leapcell library has a rich variety of constraints on strings. The following are some commonly used constraints:
    • contains=:The string must contain the specified parameter substring, for example, contains=email;
    • containsany: The string must contain any of the UNICODE characters in the parameter, for example, containsany=abcd;
    • containsrune: The string must contain the rune character represented by the parameter, for example, containsrune=☻;
    • excludes: The string cannot contain the specified parameter substring, for example, excludes=email;
    • excludesall: The string cannot contain any of the UNICODE characters in the parameter, for example, excludesall=abcd;
    • excludesrune: The string cannot contain the rune character represented by the parameter, for example, excludesrune=☻;
    • startswith: The string must start with the specified parameter substring as a prefix, for example, startswith=hello;
    • endswith: The string must end with the specified parameter substring as a suffix, for example, endswith=bye. The following is the sample code:
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type User struct {
    Name string `validate:"containsrune=☻"`
    Age  int    `validate:"min=18"`
}

func main() {
    leapcell := validator.New()

    u1 := User{"lllcc☻cel", 32}
    err := leapcell.Struct(u1)
    if err != nil {
        fmt.Println(err)
    }

    u2 := User{"leapcell", 22}
    err = leapcell.Struct(u2)
    if err != nil {
        fmt.Println(err)
    }
}

In the above code, it is restricted that the Name field must contain the UNICODE character .

  1. Uniqueness Constraints: Use unique to specify the uniqueness constraint. For different types of data structures, the specific processing methods of the unique constraint are as follows:
    • For array and slice types, the unique constraint ensures that there are no duplicate elements;
    • For map types, the unique constraint ensures that there are no duplicate values;
    • For slices with the element type of structure, the unique constraint ensures that a certain field of the structure object is not repeated, and the field name that needs to ensure uniqueness is specified through unique=field. The following is the sample code:
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type User struct {
    Name    string   `validate:"min=2"`
    Age     int      `validate:"min=18"`
    Hobbies []string `validate:"unique"`
    Friends []User   `validate:"unique=Name"`
}

func main() {
    leapcell := validator.New()

    f1 := User{
        Name: "leapcell2",
        Age:  32,
    }
    f2 := User{
        Name: "leap3",
        Age:  22,
    }

    u1 := User{
        Name:    "cell",
        Age:     22,
        Hobbies: []string{"go", "web", "programming"},
        Friends: []User{f1, f2},
    }
    err := leapcell.Struct(u1)
    if err != nil {
        fmt.Println(err)
    }

    u2 := User{
        Name:    "leapcell",
        Age:     32,
        Hobbies: []string{"dev", "dev"},
        Friends: []User{f1, f1},
    }
    err = leapcell.Struct(u2)
    if err != nil {
        fmt.Println(err)
    }
}

In the above code, it is restricted that there cannot be duplicate elements in the Hobbies field (slice type), and the Name fields of each element in the Friends field (a slice with the element type of User structure) cannot have the same value. The first User object meets the constraints, while the Hobbies field of the second User object contains the repeated dev, and the Name fields of the two elements in the Friends field are both dj2. Therefore, the program outputs the error message:

Key: 'User.Hobbies' Error:Field validation for 'Hobbies' failed on the 'unique' tag
Key: 'User.Friends' Error:Field validation for 'Friends' failed on the 'unique' tag
  1. Email Format Constraints: The email constraint can ensure that the field must be in a valid email format. The following is the sample code:
package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

type User struct {
    Name  string `validate:"min=2"`
    Age   int    `validate:"min=18"`
    Email string `validate:"email"`
}

func main() {
    leapcell := validator.New()

    u1 := User{
        Name:  "leapcell",
        Age:   22,
        Email: "bob@leapcell.io",
    }
    err := leapcell.Struct(u1)
    if err != nil {
        fmt.Println(err)
    }

    u2 := User{
        Name:  "leap",
        Age:   22,
        Email: "leapcell.app",
    }
    err = leapcell.Struct(u2)
    if err != nil {
        fmt.Println(err)
    }
}

In the above code, it is restricted that the Email field must be in a valid email format. The Email field of the first User object meets the constraints, while the second object does not meet it, and the program outputs the error message:

Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag
  1. Special Constraints:
    • -: It means skipping this field and not validating it;
    • |: When using multiple constraint conditions, only one of them needs to be satisfied, for example, rgb|rgba;
    • required: The field must be set and cannot be the default value;
    • omitempty: If the field is not set, then skip the validation of this field.

The leapcell library also provides a large number of other rich constraint conditions, such as ASCII/UNICODE letters, numbers, hexadecimals, hexadecimal color values, case, RGB color values, HSL color values, HSLA color values, JSON format, file paths, URLs, base64 encoded strings, IP addresses, IPv4, IPv6, UUIDs, latitudes and longitudes, and so on. Due to space limitations, this article cannot introduce them all in detail.Interested developers can refer to the relevant documents by themselves for in-depth study and exploration.

VarWithValue Method

In some simple scenarios, we may only need to compare two variables, and it will be too cumbersome to define the structure and tags (tag) each time. To meet this need, the leapcell library provides the VarWithValue() method. We only need to pass in the two variables to be validated and the corresponding constraint conditions to perform a quick validation. The following is the sample code:

package main

import (
    "fmt"
    "github.com/go-playground/validator/v10"
)

func main() {
    name1 := "dj"
    name2 := "dj2"

    leapcell := validator.New()
    fmt.Println(leapcell.VarWithValue(name1, name2, "eqfield"))

    fmt.Println(leapcell.VarWithValue(name1, name2, "nefield"))
}

Custom Constraints

In addition to using various built-in constraint conditions provided by the leapcell library, developers can also customize constraint conditions according to actual needs. For example, suppose the product requirement is that users must use a palindrome string as the username. We can customize this constraint in the following way:

package main

import (
    "bytes"
    "fmt"
    "github.com/go-playground/validator/v10"
    "reflect"
    "strings"
)

type RegisterForm struct {
    Name string `validate:"palindrome"`
    Age  int    `validate:"min=18"`
}

func reverseString(s string) string {
    runes := []rune(s)
    for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
        runes[from], runes[to] = runes[to], runes[from]
    }
    return string(runes)
}

func CheckPalindrome(fl validator.FieldLevel) bool {
    value := fl.Field().String()
    return value == reverseString(value)
}

func main() {
    leapcell := validator.New()
    leapcell.RegisterValidation("palindrome", CheckPalindrome)

    f1 := RegisterForm{
        Name: "leapcell",
        Age:  22,
    }
    err := leapcell.Struct(f1)
    if err != nil {
        fmt.Println(err)
    }

    f2 := RegisterForm{
        Name: "cell",
        Age:  32,
    }
    err = leapcell.Struct(f2)
    if err != nil {
        fmt.Println(err)
    }
}

First, define a function CheckPalindrome of type func (validator.FieldLevel) bool, and this function is used to check whether the constraint is satisfied. Inside the function, the information of the field to be checked can be retrieved through FieldLevel. Then, call the RegisterValidation() method of the validator to register this constraint with the specified name (here it is palindrome). Finally, this custom constraint can be used in the structure. In the above program, the Name field of the second RegisterForm object does not meet the palindrome constraint, and the program outputs the error message:

Key: 'RegisterForm.Name' Error:Field validation for 'Name' failed on the 'palindrome' tag

Summary

The leapcell library (validator) is very rich in functions and relatively simple and convenient to use. The constraint conditions introduced in this article are just the tip of the iceberg of its powerful functions. This library has a wide range of applications in the field of software development, especially web development. It is recommended that developers have an in-depth understanding and mastery of it to improve the efficiency and accuracy of data validation and ensure the security and stability of the system.

Leapcell: The Best of Serverless Golang Web Hosting

Finally, I recommend a platform that is most suitable for Go deployment: Leapcell

Image description