Data Validation in Go (Golang): Tools, Examples, and Best Practices
Data validation is one of the key stages in developing any web application or API. In Go (Golang), this task is solved particularly elegantly thanks to strong typing, powerful libraries, and built-in capabilities. In this article, we will break down the main approaches to data validation, popular libraries, and provide practical code examples.
Why is validation needed in Go?
Go compiles to native code and does not have a built-in reflection system like Python or JavaScript. However, developers have created several excellent libraries that allow you to:
- Validate struct fields against formats (email, URL, phone);
- Set constraints (min, max, required);
- Create custom validators for business logic;
- Integrate with web frameworks (Gin, Echo, Fiber).
1. The go-playground/validator library (most popular)
go-playground/validator is the de facto standard for validating structs in Go. It uses tags in struct fields and supports over 100 built-in rules.
package main
import ( "fmt" "github.com/go-playground/validator/v10")
type User struct { Name string `validate:"required,min=2,max=50"` Email string `validate:"required,email"` Age int `validate:"gte=18,lte=120"`}
func main() { validate := validator.New() user := User{ Name: "A", Email: "invalid-email", Age: 15, } err := validate.Struct(user) if err != nil { for _, e := range err.(validator.ValidationErrors) { fmt.Printf("Field: %s, Error: %s, Value: %v", e.Field(), e.Tag(), e.Value()) } }}Output:
Field: Name, Error: min, Value: AField: Email, Error: email, Value: invalid-emailField: Age, Error: gte, Value: 152. The ozzo-validation library (an alternative with method chaining)
ozzo-validation offers a more declarative style without tags. It is suitable for cases where the struct cannot be modified or dynamic validation is needed.
package main
import ( "fmt" "github.com/go-ozzo/ozzo-validation/v4" "github.com/go-ozzo/ozzo-validation/v4/is")
type Product struct { Name string Price float64}
func main() { p := Product{Name: "", Price: -10} err := validation.ValidateStruct(&p, validation.Field(&p.Name, validation.Required, validation.Length(1, 100)), validation.Field(&p.Price, validation.Required, validation.Min(0.01)), ) if err != nil { fmt.Println(err) }}3. Custom validators
Often, validation not covered by built-in rules is required. For example, password validation or name uniqueness.
package main
import ( "fmt" "github.com/go-playground/validator/v10" "unicode")
func passwordValidator(fl validator.FieldLevel) bool { pwd := fl.Field().String() hasUpper := false hasDigit := false for _, ch := range pwd { if unicode.IsUpper(ch) { hasUpper = true } if unicode.IsDigit(ch) { hasDigit = true } } return len(pwd) >= 8 && hasUpper && hasDigit}
type Account struct { Password string `validate:"password"`}
func main() { validate := validator.New() validate.RegisterValidation("password", passwordValidator)
acc := Account{Password: "weak"} err := validate.Struct(acc) if err != nil { fmt.Println("Password did not pass validation") } else { fmt.Println("Password is valid") }}4. Validating HTTP requests with Gin
The Gin framework uses
Also in library
PDF Generation in C++: Overview of Libraries and Tools
Logging in Go: Overview of the Standard log Library and Alternatives
TypeStack/class-validator for TypeScript: Complete Guide with Examples
Internationalization (i18n) in C++: A Complete Guide with gettext and ICU