govalid generates type-safe validation code from struct field markers. No reflection, no runtime overhead, just blazing fast validation.
- Zero allocations: All validation functions perform zero heap allocations
- 5x to 44x faster: Significantly outperforms reflection-based validators
- Compile-time optimization: Generated code is optimized by the Go compiler
- Type safety: Validation functions are generated with proper types, eliminating runtime reflection
- Early error detection: Invalid validation rules are caught during code generation, not at runtime
- No runtime dependencies: Generated code has minimal external dependencies
- Full collection support: Maps and channels work with size validators (not supported by most libraries)
- CEL expressions: Common Expression Language support for complex validation logic
- Go zero-value semantics: Proper handling of Go's zero values and nil states
- Unicode-aware: String validators properly handle Unicode characters
Feature | govalid | Reflection Validators |
---|---|---|
Performance | ~1-14ns, 0 allocs |
~50-700ns, 0-5 allocs |
Type Safety | β Generated functions | β Runtime reflection |
Collections | slice, array, map, channel |
slice, array only |
Dependencies | β Minimal | β Heavy runtime deps |
Error Detection | β During code generation | β Runtime |
CEL Support | β Full support | β Limited/None |
Install the govalid
command-line tool by one of supported ways:
Using go install
:
go install github.com/sivchari/govalid/cmd/govalid
Or:
# Clone the repository
git clone https://github.com/sivchari/govalid.git
# Navigate to the project directory
cd govalid
# Install the tool
go install ./...
Verify the installation:
govalid -h
// Add validation markers above your struct
// +govalid:required
type Person struct {
Name string `json:"name"`
// +govalid:email
Email string `json:"email"`
}
govalid generate
This generates validation code like:
// Code generated by govalid; DO NOT EDIT.
import (
"errors"
"github.com/sivchari/govalid"
govaliderrors "github.com/sivchari/govalid/validation/errors"
"github.com/sivchari/govalid/validation/validationhelper"
)
var (
// ErrNilPerson is returned when the Person is nil.
ErrNilPerson = errors.New("input Person is nil")
// ErrPersonNameRequiredValidation is returned when the Name is required but not provided.
ErrPersonNameRequiredValidation = govaliderrors.ValidationError{Reason: "field Name is required", Path: "Person.Name", Type: "required"}
// ErrPersonEmailEmailValidation is the error returned when the field is not a valid email address.
ErrPersonEmailEmailValidation = govaliderrors.ValidationError{Reason: "field Email must be a valid email address", Path: "Person.Email", Type: "email"}
)
var _ govalid.Validator = (*Person)(nil)
func ValidatePerson(t *Person) error {
if t == nil {
return ErrNilPerson
}
var errs govaliderrors.ValidationErrors
if t.Name == "" {
err := ErrPersonNameRequiredValidation
err.Value = t.Name
errs = append(errs, err)
}
if !validationhelper.IsValidEmail(t.Email) {
err := ErrPersonEmailEmailValidation
err.Value = t.Email
errs = append(errs, err)
}
if len(errs) > 0 {
return errs
}
return nil
}
func (p *Person) Validate() error {
return ValidatePerson(p)
}
func main() {
p := &Person{Name: "John", Email: "invalid-email"}
if err := ValidatePerson(p); err != nil {
log.Printf("Validation failed: %v", err)
// Output: Validation failed: field Email must be a valid email address
if errors.Is(err, ErrPersonEmailEmailValidation) {
log.Printf("Email validation failed, handle error as needed: %v", err)
}
}
}
In case of multiple validation errors, govalid
generated validators will aggregate all errors and return a list
of structs that implement error interface.
func main() {
p := &Person{Name: "", Email: "invalid-email"}
if err := ValidatePerson(p); err != nil {
log.Printf("Validation failed: %v", err)
if errors.Is(err, ErrPersonEmailEmailValidation) {
log.Printf("First email error", err)
}
if errors.Is(err, ErrPersonNameRequiredValidation) {
log.Printf("Second required error %v", err)
}
}
}
func main() {
p := &Person{Name: "John", Email: "invalid-email"}
if err := p.Validate(); err != nil {
log.Printf("Validation failed: %v", err)
}
}
The generated Validate()
method enables seamless integration with HTTP middleware:
import (
"net/http"
"github.com/sivchari/govalid/validation/middleware"
)
func CreatePersonHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("OK"))
}
func main() {
http.HandleFunc("/person", middleware.ValidateRequest[*Person](CreatePersonHandler))
http.ListenAndServe(":8080", nil)
}
Apply validation rules to entire structs:
// All fields will be validated as required
// +govalid:required
type Person struct {
Name string
Email string
Age int
}
Use Common Expression Language for complex validation:
type User struct {
// +govalid:cel=value >= 18 && value <= 120
Age int
// +govalid:cel=value >= this.Age
RetirementAge int
}
Validate maps, channels, slices, and arrays:
// +govalid:maxitems=10
type UserList struct {
Users []User // slice support
UserMap map[string]User // map support
UserChan chan User // channel support
}
π View Complete Marker Reference
For a complete reference of all supported markers, see MARKERS.md.
Core Validators:
required
- Field must not be zero valuegt
,gte
,lt
,lte
- Numeric comparisonsmaxlength
,minlength
- String length validationmaxitems
,minitems
- Collection size validationenum
- Enumeration validationemail
,url
,uuid
,numeric
- Format validation
Advanced:
cel
- Common Expression Language support- Struct-level markers
- Custom validation logic
govalid consistently outperforms reflection-based validators by 5x to 44x:
Validator | govalid | go-playground | Improvement |
---|---|---|---|
Required | 1.9ns |
85.5ns |
44.2x |
GT/LT | 1.9ns |
63.0ns |
32.5x |
MaxLength | 15.7ns |
73.5ns |
4.7x |
38.2ns |
649.4ns |
17.0x |
All with 0 allocations vs competitors' 0-5 allocations
For contributors, install lefthook to enable pre-commit checks:
make install-lefthook
Because of this, lefthook is installed, then the code-base would be checked automatically before each commit, ensuring code quality and consistency.
MIT License - see LICENSE file for details.