Skip to content

sivchari/govalid

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

govalid

govalid

Blazing fast, zero-allocation, type-safe validation for Go

Go Version License Build Status Go Report Card


πŸš€ Overview

govalid generates type-safe validation code from struct field markers. No reflection, no runtime overhead, just blazing fast validation.

⚑ Why govalid?

🎯 Performance Benefits

  • 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

πŸ‘¨β€πŸ’» Developer Experience

  • 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

πŸ”§ Comprehensive Go Support

  • 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

πŸ“Š Performance Comparison

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

πŸ“¦ Installation

Install the govalid command-line tool by one of supported ways:

Using go install:

Defaults to latest @ and version to install specific release

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

🎯 Quick Start

1. Define Your Struct

// Add validation markers above your struct
// +govalid:required
type Person struct {
    Name  string `json:"name"`
    // +govalid:email
    Email string `json:"email"`
}

2. Generate Validation Code

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)
}

3. Use Generated Validators

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)
		}
	}
}

3.1 Handle multiple validation errors

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)
		}
	}
}

3.2 Validator Interface

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)
}

πŸ”§ Advanced Features

Struct-Level Validation

Apply validation rules to entire structs:

// All fields will be validated as required
// +govalid:required
type Person struct {
    Name  string
    Email string
    Age   int
}

CEL Expression Support

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
}

Collection Support

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
}

πŸ“ Supported Markers

πŸ“– View Complete Marker Reference

For a complete reference of all supported markers, see MARKERS.md.

Core Validators:

  • required - Field must not be zero value
  • gt, gte, lt, lte - Numeric comparisons
  • maxlength, minlength - String length validation
  • maxitems, minitems - Collection size validation
  • enum - Enumeration validation
  • email, url, uuid, numeric - Format validation

Advanced:

  • cel - Common Expression Language support
  • Struct-level markers
  • Custom validation logic

πŸš€ Performance Benchmarks

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
Email 38.2ns 649.4ns 17.0x

All with 0 allocations vs competitors' 0-5 allocations

πŸ“Š View Complete Benchmarks

πŸ”§ Development Setup

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.

πŸ“„ License

MIT License - see LICENSE file for details.


Built with ❀️ for the Go community

About

Up to 45x faster πŸš€ Auto generate type-safe validation code for structs based on markers.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 11