guard

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2026 License: MIT Imports: 6 Imported by: 0

README

Guard

Go Reference Go Version CI

A lightweight, extensible validation library for Go with first-class support for nested structs, slices, and custom validators.

Features

  • ✅ Zero dependencies
  • ✅ Built-in validators (required, min, max, regex, oneOf, email)
  • ✅ Custom validators
  • ✅ Nested struct validation
  • ✅ Slice validation
  • ✅ Typed validation errors

Installation

go get github.com/danilosciarra/guard
import "github.com/danilosciarra/guard"

Usage

v := guard.New()

v.RegisterValidator(...)

err := v.Validate(&obj)
Basic usage
package main

import (
	"fmt"

	"github.com/danilosciarra/guard"
)

type User struct {
	Name  string `validate:"required,min=3"`
	Age   int    `validate:"min=18,max=120"`
	Email string `validate:"required,email"`
}

func main() {
	u := User{Name: "Dan", Age: 30, Email: "dan@example.com"}

	v := guard.New()
	if err := v.Validate(&u); err != nil {
		fmt.Println("validation error:", err)
		return
	}

	fmt.Println("valid")
}

Validation tags

Use the validate struct tag. Multiple rules are comma-separated.

Field string `validate:"required,min=3,max=20"`
Supported tags
Tag Syntax Applies to Description
required required string, int, float, slice, array, map, func Fails if zero/empty/nil
min min=<int> int, float, string, slice, array, map Value/length must be >= min
max max=<int> int, float, string, slice, array, map Value/length must be <= max
regex regex=<pattern> any (converted to string) Must match the Go regexp pattern
oneOf oneOf=a|b|c string, int, float Value must be one of the pipe-separated options
email email string Must be a valid email address (no display name)
Type support matrix
Tag string int/uint float slice/array/map func pointer
required ✓ ✓ ✓ ✓ ✓ ✓ (dereferenced)
min ✓ (len) ✓ ✓ ✓ (len) — ✓ (dereferenced)
max ✓ (len) ✓ ✓ ✓ (len) — ✓ (dereferenced)
regex ✓ ✓ (fmt) ✓ (fmt) — — —
oneOf ✓ ✓ (fmt) ✓ (fmt) — — ✓ (dereferenced)
email ✓ — — — — —

Pointers and interfaces are automatically dereferenced before validation. Nil pointers return false for required and all numeric/string validators.

Multiple rules on the same field

type Product struct {
	Code  string  `validate:"required,regex=^[A-Z0-9_-]+$"`
	Price float64 `validate:"min=1,max=9999"`
}

Rules are evaluated left-to-right. Validation stops at the first failing rule.

Custom validators

You can register custom validators by tag name.

type Payload struct {
	Token string `validate:"token_prefix"`
}

v := guard.New()
v.RegisterValidator("token_prefix", func(path string, value any) bool {
	s, ok := value.(string)
	if !ok {
		return false
	}
	return len(s) > 4 && s[:4] == "tok_"
})

err := v.Validate(&Payload{Token: "tok_123"})

If a custom validator is registered for a tag, it is used instead of built-in validator parsing.

Nested structs and slices

The package traverses:

  • nested structs
  • pointers to structs (nil pointers are skipped unless a direct tagged field is evaluated)
  • slices of structs

For slices of structs, when items have an Id string field, that value may be used internally for path resolution.

Example with nested data
type Address struct {
	City string `validate:"required"`
}

type Customer struct {
	Id      string   `validate:"required"`
	Name    string   `validate:"required,min=2"`
	Address *Address `validate:"required"`
}

type Order struct {
	Items []Customer
}

order := Order{
	Items: []Customer{
		{Id: "c1", Name: "Alice", Address: &Address{City: "Rome"}},
	},
}

v := guard.New()
err := v.Validate(&order)

Error handling

Validate returns error.

  • err == nil: all validations passed
  • err != nil: validation failed or invalid configuration/input

The package defines typed errors in errors.go:

  • *guard.ValidationError
  • *guard.PathError
  • *guard.TypeMismatchError
  • *guard.InvalidInputError

Validator parsing errors come from the validator package and are wrapped with context.

Example: inspect error type
if err := v.Validate(&u); err != nil {
	switch e := err.(type) {
	case *guard.ValidationError:
		fmt.Println("field:", e.FieldPath, "tag:", e.Tag, "value:", e.Value)
	case *guard.InvalidInputError:
		fmt.Println("invalid input:", e.Reason)
	default:
		fmt.Println("error:", err)
	}
}

Common pitfalls

  • Unknown tag names return validation/parsing errors.
  • min/max parameters must be integers.
  • email validator expects a string value.
  • regex uses Go regexp syntax.

License

This project is distributed under the terms in LICENSE.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Guard

type Guard struct {
	// contains filtered or unexported fields
}

func New

func New() *Guard

func (*Guard) RegisterValidator

func (m *Guard) RegisterValidator(tag string, val customValidationFunction)

func (*Guard) Validate

func (m *Guard) Validate(obj any) error

type InvalidInputError

type InvalidInputError struct {
	Reason string
}

func (*InvalidInputError) Error

func (e *InvalidInputError) Error() string

type PathError

type PathError struct {
	Path   string
	Reason string
}

func (*PathError) Error

func (e *PathError) Error() string

type TagParseError

type TagParseError struct {
	Tag    string
	Reason string
}

func (*TagParseError) Error

func (e *TagParseError) Error() string

type TypeMismatchError

type TypeMismatchError struct {
	Expected string
	Actual   string
	Field    string
}

func (*TypeMismatchError) Error

func (e *TypeMismatchError) Error() string

type ValidationError

type ValidationError struct {
	FieldPath string
	Value     any
	Tag       string
	Reason    string
}

func (*ValidationError) Error

func (e *ValidationError) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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