xvalidator

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jan 6, 2026 License: MIT Imports: 13 Imported by: 0

README

go-xvalidator

A powerful extension package for go-playground/validator that provides enhanced validation capabilities including decimal validation, phone number validation (E.164 format), URL validation, password strength validation, and localized error messages for Go applications.

Go Version License

Features

  • 🔢 Decimal Validation: Precise decimal comparison operators (greater than, less than, equal, etc.)
  • 📱 Phone Validation: International phone number validation with country-specific rules (E.164 format)
  • 🔗 URL Validation: Standard and HTTPS-only URL validation
  • 🔒 Password Strength: Comprehensive password strength validation
  • 🌍 Localization: Built-in English translations for validation errors
  • ✨ Easy Integration: Drop-in replacement for go-playground/validator

Table of Contents

Installation

go get github.com/hotfixfirst/go-xvalidator

Quick Start

package main

import (
    "fmt"
    "github.com/hotfixfirst/go-xvalidator"
)

func main() {
    // Create validator instance
    v, err := xvalidator.NewValidator()
    if err != nil {
        panic(err)
    }

    // Define your struct with validation tags
    type User struct {
        Name     string `json:"name" validate:"required,min=3"`
        Email    string `json:"email" validate:"required,email"`
        Phone    string `json:"phone" validate:"mobile_e164=US"`
        Balance  string `json:"balance" validate:"dgte=0"`
        Password string `json:"password" validate:"password_strength"`
    }

    // Validate
    user := User{
        Name:     "John Doe",
        Email:    "john.doe@example.com",
        Phone:    "+447912345678",
        Balance:  "1000.50",
        Password: "SecureP@ss123",
    }

    if err := v.Validate(user); err != nil {
        fmt.Printf("Validation failed: %v\n", err)
        return
    }

    fmt.Println("Validation passed!")
}

Available Validators

Decimal Validators

Validate decimal values with precise comparison:

type Product struct {
    Price    string `validate:"required,dgte=0,dlte=999999.99"`
    Discount string `validate:"dgte=0,dlte=100"`
    Quantity string `validate:"dgt=0"`
}

Tags:

  • decimal - Validates decimal format (precision and scale)
  • dgt=value - Decimal greater than
  • dgte=value - Decimal greater than or equal
  • dlt=value - Decimal less than
  • dlte=value - Decimal less than or equal
  • deq=value - Decimal equal to
  • dneq=value - Decimal not equal to
Conditional Decimal Validators

Validate decimals conditionally based on other field values:

type Payment struct {
    Method string `validate:"required,oneof=cash credit_card"`
    Amount string `validate:"required,decimal_if=Method cash dgte 0 decimal 10:0"`
    // Amount must be integer (0 decimals) if Method is "cash"
}

Tag:

  • decimal_if=FieldName FieldValue Operator CompareValue DecimalFormat
    • Only validates if FieldName equals FieldValue
    • Supports: dgt, dgte, dlt, dlte, deq, dneq
    • DecimalFormat: precision:scale (e.g., 10:2)
Phone Number Validators

Validate international phone numbers in E.164 format:

type Contact struct {
    PhoneGeneral string `validate:"mobile_e164"`        // Any country
    PhoneTH      string `validate:"mobile_e164=TH"`     // Thai mobile
    PhoneUS      string `validate:"mobile_e164=US"`     // US mobile
    PhoneGB      string `validate:"mobile_e164=GB"`     // UK mobile
}

Supported Countries:

  • TH - Thailand
  • US - United States
  • GB - United Kingdom
  • FR - France
  • And many more...
URL Validators

Validate URL formats:

type Website struct {
    Homepage string `validate:"url"`              // Any valid URL
    SecureAPI string `validate:"https_url"`       // HTTPS only
}
Password Strength Validator

Validate password complexity:

type Account struct {
    Password string `validate:"password_strength"`
}

// Or use standalone validation
err := xvalidator.ValidatePasswordStrength("MyP@ssw0rd")

Requirements:

  • Minimum 8 characters
  • At least one uppercase letter
  • At least one lowercase letter
  • At least one digit
  • At least one special character: !@#$%^&*()_+-=[]{}|;:,.<>?

Examples

See the _examples/ directory for 131 comprehensive examples across 10 categories.

📚 Example Categories
Getting Started
  • basic/ - Basic validation (10 examples)
    • Required fields, email, min/max validation
Feature-Specific
  • decimal/ - Decimal validation (22 examples)

    • Standard comparisons (dgt, dgte, dlt, dlte, deq, dneq)
    • Conditional validation (decimal_if)
    • Precision and scale validation
  • phone/ - E.164 phone validation (12 examples)

    • International formats (TH, US, UK, FR, DE, JP, etc.)
  • url/ - URL validation (13 examples)

    • HTTP/HTTPS validation with paths and parameters
  • password/ - Password strength (14 examples)

    • Complexity requirements and edge cases
Advanced Usage
  • nested-struct/ - Nested structures (10 examples)

    • Complex object validation with dive
  • custom-messages/ - Error translation (11 examples)

    • Localized messages and custom formats
  • advanced/ - Custom validators (5 examples)

    • Thai ID Card, Business Hours, Custom validators
  • real-world/ - Real scenarios (27 examples)

    • User registration, Payment processing, E-commerce orders
  • best-practices/ - Recommended patterns (7 examples)

    • String validation + decimal.Decimal workflow
🚀 Running Examples
# Run any example
cd _examples/basic
go run main.go

# Decimal has 2 files (run separately)
cd _examples/decimal
go run main.go
go run conditional.go

# Real-world has 3 files (run individually)
cd _examples/real-world
go run user-registration.go
go run payment.go
go run ecommerce.go

For complete documentation, see _examples/README.md

Best Practices

Decimal Handling for Monetary Values

✅ Recommended Pattern:

import "github.com/shopspring/decimal"

// 1. Use string in API/struct layer
type PriceRequest struct {
    Amount string `json:"amount" validate:"required,decimal=10:2,dgt=0"`
}

// 2. Validate using xvalidator
if err := validator.StructTranslated(req); err != nil {
    return err
}

// 3. Convert to decimal.Decimal for calculations
amount, _ := decimal.NewFromString(req.Amount)
tax := amount.Mul(decimal.NewFromFloat(0.07))
total := amount.Add(tax)

// 4. Format back to string for output
return total.StringFixed(2)

Why this pattern?

  • ✅ Prevents floating-point precision errors
  • ✅ Validates before processing
  • ✅ Maintains accuracy in calculations
  • ✅ Consistent between validation and business logic

❌ Avoid:

// Don't use float64 for money
type BadRequest struct {
    Amount float64 `json:"amount"` // ❌ Precision errors!
}

// Don't use decimal.Decimal directly in API structs
type BadRequest struct {
    Amount decimal.Decimal `json:"amount"` // ❌ JSON marshaling issues!
}

See _examples/best-practices/decimal-workflow.go for complete working examples.

Custom Validators

Create reusable custom validators:

func validateBusinessHours(fl validator.FieldLevel) bool {
    timeStr := fl.Field().String()
    t, err := time.Parse("15:04", timeStr)
    if err != nil {
        return false
    }
    
    start, _ := time.Parse("15:04", "09:00")
    end, _ := time.Parse("15:04", "17:00")
    
    return t.After(start) && t.Before(end)
}

// Register
v.GetValidator().RegisterValidation("business_hours", validateBusinessHours)

See _examples/advanced/main.go for more custom validator examples.

Testing

Run the test suite:

go test -v ./...

Run tests with coverage:

go test -v -cover ./...

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Built on top of the excellent go-playground/validator library.

Support

For questions and issues, please open an issue on GitHub.

Documentation

Index

Constants

View Source
const (
	// DefaultPrecision defines the default precision for decimal validation (total digits).
	DefaultPrecision = 38

	// DefaultScale defines the default scale for decimal validation (decimal places).
	DefaultScale = 18
)

Decimal validation default values

Variables

View Source
var (
	// E164Regex returns a compiled regex for validating E.164 phone numbers.
	E164Regex = lazyRegexCompile(e164RegexString)
)

Pre-compiled regex functions

Functions

func RegisterDecimalValidators

func RegisterDecimalValidators(v *validator.Validate)

RegisterDecimalValidators registers all decimal validation rules for shopspring/decimal.Decimal type. This function adds comprehensive decimal comparison validators that work with decimal.Decimal values.

func RegisterPasswordValidators

func RegisterPasswordValidators(v *validator.Validate)

RegisterPasswordValidators registers password validation rules. This function adds validators for password strength and complexity requirements.

func RegisterPhoneValidators

func RegisterPhoneValidators(v *validator.Validate)

RegisterPhoneValidators registers phone number validation rules using libphonenumber. This function adds validators for international phone number format and type validation.

func RegisterURLValidators

func RegisterURLValidators(v *validator.Validate)

RegisterURLValidators registers URL-specific validation rules. This function adds validators for URL format and protocol validation.

func ValidatePasswordStrength

func ValidatePasswordStrength(password string) error

ValidatePasswordStrength provides a public interface to validate password strength. Returns an error if the password doesn't meet the requirements.

Types

type Validator

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

Validator wraps go-playground/validator with enhanced decimal support and Universal Translator.

func NewValidator

func NewValidator() (*Validator, error)

NewValidator creates a new validator instance with all custom rules and English translator registered.

func (*Validator) GetTranslator

func (v *Validator) GetTranslator() ut.Translator

GetTranslator returns the Universal Translator instance.

func (*Validator) GetValidator

func (v *Validator) GetValidator() *validator.Validate

GetValidator returns the underlying validator.Validate instance.

func (*Validator) Struct

func (v *Validator) Struct(i any) error

Struct validates a struct and returns raw validation errors without translation. This method is an alias for Validate for consistency with other validator methods.

func (*Validator) StructTranslated

func (v *Validator) StructTranslated(s any) error

StructTranslated validates a struct based on tags and returns user-friendly translated error messages.

func (*Validator) Validate

func (v *Validator) Validate(i any) error

Validate validates a struct and returns raw validation errors without translation. For user-friendly error messages, use StructTranslated instead.

func (*Validator) Var

func (v *Validator) Var(field any, tag string) error

Var validates a single variable using the provided validation tag and returns raw errors. For user-friendly error messages, use VarTranslated instead.

func (*Validator) VarTranslated

func (v *Validator) VarTranslated(field any, tag string) error

VarTranslated validates a single variable using the provided validation tag and returns user-friendly translated error messages.

Directories

Path Synopsis
_examples
advanced command
basic command
best-practices command
custom-messages command
decimal command
nested-struct command
password command
phone command
real-world command
url command

Jump to

Keyboard shortcuts

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