validate

package module
v3.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2025 License: MIT Imports: 5 Imported by: 0

README

validate

Composable validation for Go with fluent builders, rule tags, struct validation, and optional message translation.

Packages

  • github.com/aatuh/validate/v3: main API (Validate, builders, FromTag)
  • github.com/aatuh/validate/v3/core: generic validation engine (unified, cache-optimized)
  • github.com/aatuh/validate/v3/glue: integration layer with builders
  • github.com/aatuh/validate/v3/validators: type-specific rules
  • github.com/aatuh/validate/v3/errors: error types and codes
  • github.com/aatuh/validate/v3/structvalidator: struct validation
  • github.com/aatuh/validate/v3/translator: i18n helpers

The package is architecturally separated into:

  • Core: Generic validation engine, type-agnostic, with unified caching
  • Glue: Integration layer that connects core with type-specific builders
  • Validators: Type-specific validation implementations

Quick start

Basic validation
package main

import (
    "fmt"
    "github.com/aatuh/validate/v3"
)

func main() {
    v := validate.New()

    // String: call Build() to get func(any) error.
    nameV := v.String().MinLength(3).MaxLength(50).Build()
    if err := nameV("John"); err != nil {
        fmt.Println("validation failed:", err)
    }

    // Int: call Build() to obtain func(any) error.
    ageV := v.Int().MinInt(18).MaxInt(120).Build()
    if err := ageV(25); err != nil {
        fmt.Println("validation failed:", err)
    }

    // FromTag: compile single tag strings (more convenient than FromRules)
    tagV, _ := v.FromTag("string;min=3;max=50")
    if err := tagV("John"); err != nil {
        fmt.Println("validation failed:", err)
    }
}
Slice validation with element rules
import (
    "github.com/aatuh/validate/v3"
    "github.com/aatuh/validate/v3/types"
)

v := validate.New()

// Method 1: ForEach with function (not cache-friendly)
tagElem := v.String().MinLength(2).Build()
tagsV := v.Slice().MinSliceLength(1).ForEach(tagElem).Build()

// Method 2: ForEachRules (cache-friendly, better performance)
tagsV2 := v.Slice().MinSliceLength(1).ForEachRules(
    types.NewRule(types.KString, nil),
    types.NewRule(types.KMinLength, map[string]any{"n": int64(2)}),
).Build()

// Method 3: ForEachStringBuilder (convenience for string elements)
stringBuilder := v.String().MinLength(2)
tagsV3 := v.Slice().MinSliceLength(1).ForEachStringBuilder(stringBuilder).Build()

if err := tagsV([]string{"go", "lib"}); err != nil {
    fmt.Println("validation failed:", err)
}
Struct validation
package main

import (
    "fmt"
    "github.com/aatuh/validate/v3"
    verrs "github.com/aatuh/validate/v3/errors"
    "github.com/aatuh/validate/v3/structvalidator"
)

type User struct {
    Name     string   `validate:"string;min=3;max=50"`
    Website  string   `validate:"string;min=5;max=100"`
    Age      int      `validate:"int;min=18;max=120"`
    ID       string   `validate:"string;min=5;max=20"`
    Tags     []string `validate:"slice;min=1;max=5;foreach=(string;min=2)"`
    Status   string   `validate:"string;oneof=active,inactive,pending"`
    Bio      string   `validate:"string;maxRunes=500"` // Unicode-aware length
}

func main() {
    v := validate.New()
    sv := structvalidator.NewStructValidator(v)

    u := User{
        Name:    "John Doe", 
        Website: "https://example.com", 
        Age:     25,
        ID:      "user123",
        Tags:    []string{"golang", "validation"},
        Status:  "active",
        Bio:     "Software developer",
    }
    if err := sv.ValidateStruct(u); err != nil {
        if es, ok := err.(verrs.Errors); ok {
            fmt.Println("errors:", es.AsMap())
        } else {
            fmt.Println("validation failed:", err)
        }
    }
}
With translation
package main

import (
    "fmt"
    "github.com/aatuh/validate/v3"
    "github.com/aatuh/validate/v3/translator"
)

func main() {
    msgs := map[string]string{
        "string.minLength": "doit contenir au moins %d caractères",
        "string.maxLength": "ne peut pas dépasser %d caractères",
    }
    tr := translator.NewSimpleTranslator(msgs)

    v := validate.New().WithTranslator(tr)

    check := v.String().MinLength(5).MaxLength(10).Build()
    if err := check("ab"); err != nil {
        fmt.Println("fr:", err)
    }
}

Tip: translator.DefaultEnglishTranslations() provides sensible defaults.

FromTag convenience

For single tag strings, use FromTag instead of FromRules:

v := validate.New()

// More convenient than FromRules([]string{"string;min=3;max=50"})
validator, _ := v.FromTag("string;min=3;max=50")
if err := validator("hello"); err != nil {
    fmt.Println("validation failed:", err)
}

// Root-level FromTag (works with nil Validate)
validator2, _ := validate.FromTag(nil, "int;min=1;max=100")
if err := validator2(50); err != nil {
    fmt.Println("validation failed:", err)
}
Builder caching

The validation package includes automatic caching for builder validators to improve performance when the same validation rules are used repeatedly:

v := validate.New()

// First call compiles and caches the validator
validator1 := v.String().MinLength(3).MaxLength(50).Build()

// Subsequent calls with identical rules return cached validator
validator2 := v.String().MinLength(3).MaxLength(50).Build()
// validator1 and validator2 are the same cached function

// Different rules create new validators
validator3 := v.String().MinLength(5).MaxLength(20).Build() // Different cache key

The cache uses rule serialization to create unique keys, so identical rule combinations are automatically cached for optimal performance.

Cache-friendly slice validation

For better performance with slice validation, use ForEachRules instead of ForEach:

v := validate.New()

// Cache-friendly: uses AST rules (cached)
sliceValidator := v.Slice().MinLength(1).ForEachRules(
    types.NewRule(types.KString, nil),
    types.NewRule(types.KMinLength, map[string]any{"n": int64(2)}),
).Build()

// Not cache-friendly: uses function closure (not cached)
elemValidator := v.String().MinLength(2).Build()
sliceValidator2 := v.Slice().MinLength(1).ForEach(elemValidator).Build()

API reference

Validate
v := validate.New()
v = v.WithTranslator(tr)
v = v.PathSeparator(".")

// FromTag convenience
validator, _ := v.FromTag("string;min=3;max=50")

// Root-level FromTag
validator2, _ := validate.FromTag(nil, "int;min=1;max=100")

custom := map[string]func(any) error{
    "customRule": func(v any) error { return nil },
}
v2 := validate.NewWithCustomRules(custom)
Builders
// String
strV := v.String().MinLength(3).MaxLength(50).Regex(`^[a-z0-9_]+$`).Build()

// Int (accepts any Go int type at call time)
intV := v.Int().MinInt(0).MaxInt(100).Build()

// Int64 (requires exactly int64 at call time)
int64V := v.Int64().MinInt(0).MaxInt(100).Build()

// Slice
elem := v.String().MinLength(2).Build()
sliceV := v.Slice().MinSliceLength(1).ForEach(elem).Build()

// Cache-friendly slice validation
sliceV2 := v.Slice().MinSliceLength(1).ForEachRules(
    types.NewRule(types.KString, nil),
    types.NewRule(types.KMinLength, map[string]any{"n": int64(2)}),
).Build()

// Convenience method for string elements
stringBuilder := v.String().MinLength(2)
sliceV3 := v.Slice().MinSliceLength(1).ForEachStringBuilder(stringBuilder).Build()

// Bool
boolV := v.Bool() // type-check only
Struct tags
type Example struct {
    Name    string   `validate:"string;min=3;max=50"`
    Website string   `validate:"string;min=5;max=100"`
    Age     int      `validate:"int;min=18;max=120"`
    Tags    []string `validate:"slice;min=1;max=5"`
    Flag    bool     `validate:"bool"`
}

Supported tokens:

  • string: len, min, max, minRunes, maxRunes, oneof=a,b,c (or space-separated), regex=...
  • int/int64: min, max (use int64;... to require int64)
  • slice: len, min, max, foreach=(string;min=2) (nested rules)
  • bool: type only
Errors

Struct validation returns errors.Errors which offers helpers:

if es, ok := err.(verrs.Errors); ok {
    _ = es.Has("Name")
    _ = es.Filter("") // or a nested prefix like "Address."
    _ = es.AsMap()
}

Note: direct builder calls usually return a single error, not an errors.Errors aggregate.

Error codes

Stable constants for programmatic handling (see errors/codes.go):

const (
    // String
    CodeStringMin = "string.min"
    CodeStringMax = "string.max"
    CodeStringNonEmpty = "string.nonempty"
    CodeStringPattern = "string.pattern"
    CodeStringOneOf = "string.oneof"

    // Number (ints/floats)
    CodeNumberMin = "number.min"
    CodeNumberMax = "number.max"

    // Slice
    CodeSliceMin = "slice.min"
    CodeSliceMax = "slice.max"
)

Documentation

Overview

Package validate provides composable validation helpers for Go with fluent builders, rule tags, and struct validation. It includes optional message translation support.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FromTag

func FromTag(v *Validate, tag string) (func(any) error, error)

FromTag compiles a single tag string using v (or a fresh instance).

Types

type BoolBuilder

type BoolBuilder = glue.BoolBuilder

type IntBuilder

type IntBuilder = glue.IntBuilder

type SliceBuilder

type SliceBuilder = glue.SliceBuilder

type StringBuilder

type StringBuilder = glue.StringBuilder

type Validate

type Validate = glue.Validate

Re-export glue types for a developer-friendly root facade.

func New

func New() *Validate

New returns a Validate configured with sensible defaults.

Defaults: - Installs default English translations via SimpleTranslator. - Registers built-in plugins (email, ulid, uuid) via blank imports.

func NewBare

func NewBare() *Validate

NewBare returns a Validate without installing a default translator. Useful for advanced setups that manage translations differently.

func NewWithTranslator

func NewWithTranslator(tr translator.Translator) *Validate

NewWithTranslator returns a Validate configured with the provided translator while keeping other defaults.

Directories

Path Synopsis
Package core provides the main validation engine and fluent builder APIs.
Package core provides the main validation engine and fluent builder APIs.
Package errors provides error types and error handling utilities for validation.
Package errors provides error types and error handling utilities for validation.
Package structvalidator provides struct validation functionality using reflection.
Package structvalidator provides struct validation functionality using reflection.
Package translator provides internationalization support for validation messages.
Package translator provides internationalization support for validation messages.
Package types provides the core validation engine types and rule system.
Package types provides the core validation engine types and rule system.
Package validators provides built-in validation rules and plugin architecture.
Package validators provides built-in validation rules and plugin architecture.
email
Package email provides email address validation as a plugin.
Package email provides email address validation as a plugin.
ulid
Package ulid provides ULID validation as a plugin.
Package ulid provides ULID validation as a plugin.
uuid
Package uuid provides UUID validation as a plugin.
Package uuid provides UUID validation as a plugin.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL