Data Validation in Go (Golang): A Complete Guide to Libraries and Approaches
Data validation is a critical part of any web application, API, or microservice. In Go (Golang), this task is handled both by standard tools and powerful third-party libraries. In this article, we will cover the main approaches, popular libraries, and provide practical code examples.
Why is validation needed in Go?
Go is a strongly typed language, which already provides some protection against incorrect data. However, types do not check business rules: an email must contain "@", age must be in the range 0–120, a password must have a minimum length. Without validation, you risk getting:
- SQL injections and XSS attacks
- Incorrect data in the database
- Unexpected panics and runtime errors
Built-in validation tools
The simplest validation is done "manually" in functions. Example:
type User struct { Name string Email string Age int}
func ValidateUser(u User) error { if u.Name == "" { return errors.New("name is required") } if !strings.Contains(u.Email, "@") { return errors.New("invalid email") } if u.Age < 0 || u.Age > 150 { return errors.New("age must be between 0 and 150") } return nil}This approach is simple, but for complex structures it becomes cumbersome and hard to maintain. Therefore, the Go community has created specialized libraries.
1. go-playground/validator — the de facto standard
Link: github.com/go-playground/validator/v10
This is the most popular validation library in Go (over 15k stars on GitHub). It uses struct tags for declarative rule descriptions.
Installation
go get github.com/go-playground/validator/v10Usage example
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=0,lte=150"` Password string `validate:"required,min=8"`}
func main() { validate := validator.New()
user := User{ Name: "A", Email: "not-email", Age: 200, Password: "123", }
err := validate.Struct(user) if err != nil { for _, e := range err.(validator.ValidationErrors) { fmt.Printf("Field: %s, Rule: %s, Value: %v", e.Field(), e.Tag(), e.Value()) } }}Output:
Field: Name, Rule: min, Value: AField: Email, Rule: email, Value: not-emailField: Age, Rule: lte, Value: 200Field: Password, Rule: min, Value: 123Popular tag rules
required— field is mandatorymin,max— for numbers and stringslen— exact lengthemail— email validationurl— URL validationgte,lte— greater than/less than or equaloneof— one of the values (oneof=admin user)
Custom validators
validate.RegisterValidation("is-odd", func(fl validator.FieldLevel) bool { return fl.Field().Int()%2 != 0})
type MyStruct struct { Number int `validate:"is-odd"`}2. ozzo-validation — an alternative with chains
Link: github.com/go-ozzo/ozzo-validation/v4
This library offers a more "Go-idiomatic" approach: rules are defined through functions rather than tags. This provides greater flexibility and readability.
Example
package main
import ( "fm Also in library
Java PDF Report Generation: Libraries and Examples
Prometheus Metrics in TypeScript: Complete Guide to client.js
Working with ZIP Archives in Rust: The zip Library and Complete Guide
Parsing HTML in C++: Libraries and Examples for Working with DOM and XPath