Documentation
¶
Overview ¶
Package validator provides a rule-based data validation system with both programmatic and struct tag-based validation capabilities.
The package is built around a Rule type that encapsulates validation logic and error reporting, allowing for flexible and composable validation patterns.
Core Concepts ¶
Rules are created by validation functions that return a Rule struct containing both the validation check and error details:
import "github.com/dmitrymomot/forge/pkg/validator"
// Create validation rules
rules := []validator.Rule{
validator.Required("username", user.Username),
validator.MinLen("username", user.Username, 3),
validator.ValidEmail("email", user.Email),
}
// Apply all rules
if err := validator.Apply(rules...); err != nil {
// Handle validation errors
validationErrs := validator.ExtractValidationErrors(err)
for _, verr := range validationErrs {
fmt.Printf("Field: %s, Message: %s\n", verr.Field, verr.Message)
}
}
String Validation ¶
String validation functions for common requirements:
rules := []validator.Rule{
validator.Required("name", user.Name),
validator.MinLen("name", user.Name, 2),
validator.MaxLen("name", user.Name, 50),
validator.ValidEmail("email", user.Email),
validator.ValidURL("website", user.Website),
validator.ValidPhone("phone", user.Phone),
validator.ValidAlphanumeric("username", user.Username),
}
Numeric Validation ¶
Type-safe numeric validation using generics:
rules := []validator.Rule{
validator.Min("age", user.Age, 18),
validator.Max("age", user.Age, 120),
validator.Min("price", product.Price, 0.01),
validator.Max("quantity", order.Quantity, 1000),
}
Collection Validation ¶
Validation for slices and maps:
rules := []validator.Rule{
validator.RequiredSlice("items", order.Items),
validator.MinLenSlice("items", order.Items, 1),
validator.MaxLenSlice("tags", post.Tags, 10),
validator.RequiredMap("metadata", user.Metadata),
}
Choice Validation ¶
Validate values against allowed/forbidden lists:
validStatuses := []string{"active", "inactive", "pending"}
rules := []validator.Rule{
validator.InList("status", user.Status, validStatuses),
}
forbiddenUsernames := []string{"admin", "root", "system"}
rules = append(rules,
validator.NotInList("username", user.Username, forbiddenUsernames),
)
UUID Validation ¶
UUID validation with version support:
import "github.com/google/uuid"
rules := []validator.Rule{
validator.ValidUUID("id", user.ID),
validator.ValidUUIDv4String("session_id", session.ID),
validator.RequiredUUID("user_id", userUUID),
}
Format Validation ¶
Various format validators:
rules := []validator.Rule{
validator.ValidEmail("email", user.Email),
validator.ValidURL("website", user.Website),
validator.ValidURLWithScheme("api_url", config.APIURL, []string{"https"}),
validator.ValidPhone("phone", user.Phone),
validator.ValidIPv4("server", config.ServerIP),
validator.ValidMAC("device_mac", device.MACAddress),
}
Financial Validation ¶
Financial data validation:
rules := []validator.Rule{
validator.PositiveAmount("amount", payment.Amount),
validator.ValidCurrencyCode("currency", payment.Currency),
validator.ValidCreditCardChecksum("card_number", payment.CardNumber),
validator.DecimalPrecision("price", product.Price, 2),
validator.ValidPercentage("tax_rate", order.TaxRate),
}
Pattern Validation ¶
Regular expression and pattern matching:
rules := []validator.Rule{
validator.MatchesRegex("sku", product.SKU, `^[A-Z]{2}\d{4}$`, "product SKU"),
validator.NoWhitespace("api_key", config.APIKey),
validator.PrintableChars("description", item.Description),
}
Struct Tag Validation ¶
The package supports struct tag-based validation:
type User struct {
Username string `validate:"required;min:3;max:20;alphanum"`
Email string `validate:"required;email"`
Age int `validate:"min:18;max:120"`
Status string `validate:"in:active,inactive,pending"`
}
user := User{
Username: "john_doe",
Email: "john@example.com",
Age: 25,
Status: "active",
}
if err := validator.ValidateStruct(&user); err != nil {
// Handle validation errors
validationErrs := validator.ExtractValidationErrors(err)
for _, verr := range validationErrs {
fmt.Printf("%s: %s\n", verr.Field, verr.Message)
}
}
Custom Validators ¶
Register custom validation functions for struct tags:
validator.RegisterValidator("business_email", func(field string, value reflect.Value, params []string) validator.Rule {
email := value.String()
return validator.Rule{
Check: func() bool {
// Custom business email validation logic
return strings.HasSuffix(email, "@company.com")
},
Error: validator.ValidationError{
Field: field,
Message: "must be a company email address",
},
}
})
Error Handling ¶
ValidationErrors provides methods for working with validation results:
if err := validator.Apply(rules...); err != nil {
if validator.IsValidationError(err) {
validationErrs := validator.ExtractValidationErrors(err)
// Check for specific field errors
if validationErrs.Has("email") {
emailErrors := validationErrs.Get("email")
fmt.Println("Email errors:", emailErrors)
}
// Get all failed fields
failedFields := validationErrs.Fields()
fmt.Println("Failed fields:", failedFields)
}
}
Translation Support ¶
ValidationError includes translation keys and values for internationalization. Use the Translate method on ValidationErrors with a TranslateFunc to translate all error messages in a single call. The i18n Translator.TranslateMessage method matches TranslateFunc directly:
if err := validator.Apply(rules...); err != nil {
ve := validator.ExtractValidationErrors(err)
ve.Translate(translator.TranslateMessage) // translates Message fields in-place
for _, verr := range ve {
fmt.Printf("%s: %s\n", verr.Field, verr.Message)
}
}
Index ¶
- func Apply(rules ...Rule) error
- func IsValidationError(err error) bool
- func RegisterValidator(name string, fn ValidatorFunc)
- func ValidateStruct(v any) error
- type Numeric
- type PasswordStrengthConfig
- type Rule
- func ASCIIOnly(field, value string) Rule
- func AgeBetween(field string, birthdate time.Time, minAge int, maxAge int) Rule
- func AmountRange[T Numeric](field string, value T, min T, max T) Rule
- func BalancedParentheses(field, value string) Rule
- func BusinessHours(field string, value time.Time, startHour int, endHour int) Rule
- func ContainsDigit(field, value string) Rule
- func ContainsLowercase(field, value string) Rule
- func ContainsPattern(field, value string, pattern string, description string) Rule
- func ContainsUppercase(field, value string) Rule
- func CurrencyPrecision(field string, value float64, decimals int) Rule
- func DateAfter(field string, value time.Time, after time.Time) Rule
- func DateBefore(field string, value time.Time, before time.Time) Rule
- func DateBetween(field string, value time.Time, start time.Time, end time.Time) Rule
- func DecimalPrecision(field string, value float64, maxDecimals int) Rule
- func DoesNotMatchRegex(field, value string, pattern string, description string) Rule
- func EndsWithPattern(field, value string, pattern string) Rule
- func FutureDate(field string, value time.Time) Rule
- func InList[T comparable](field string, value T, allowedValues []T) Rule
- func InListCaseInsensitive(field, value string, allowedValues []string) Rule
- func InListString(field, value string, allowedValues []string) Rule
- func Len(field, value string, exact int) Rule
- func LenMap[K comparable, V any](field string, value map[K]V, exact int) Rule
- func LenSlice[T any](field string, value []T, exact int) Rule
- func LenString(field, value string, exact int) Rule
- func LineCount(field, value string, min int, max int) Rule
- func MatchesRegex(field, value string, pattern string, description string) Rule
- func Max[T Numeric](field string, value T, max T) Rule
- func MaxAge(field string, birthdate time.Time, maxAge int) Rule
- func MaxLen(field, value string, max int) Rule
- func MaxLenMap[K comparable, V any](field string, value map[K]V, max int) Rule
- func MaxLenSlice[T any](field string, value []T, max int) Rule
- func MaxLenString(field, value string, max int) Rule
- func MaxNum[T Numeric](field string, value T, max T) Rule
- func MaximumTransaction[T Numeric](field string, value T, maximum T) Rule
- func Min[T Numeric](field string, value T, min T) Rule
- func MinAge(field string, birthdate time.Time, minAge int) Rule
- func MinLen(field, value string, min int) Rule
- func MinLenMap[K comparable, V any](field string, value map[K]V, min int) Rule
- func MinLenSlice[T any](field string, value []T, min int) Rule
- func MinLenString(field, value string, min int) Rule
- func MinNum[T Numeric](field string, value T, min T) Rule
- func MinimumPurchase[T Numeric](field string, value T, minimum T) Rule
- func NoControlChars(field, value string) Rule
- func NoRepeatingChars(field, value string, maxRepeats int) Rule
- func NoSequentialChars(field, value string, maxSequential int) Rule
- func NoSpecialChars(field, value string) Rule
- func NoWhitespace(field, value string) Rule
- func NonNegativeAmount[T Numeric](field string, value T) Rule
- func NonNilUUID(field string, value uuid.UUID) Rule
- func NonNilUUIDString(field, value string) Rule
- func NoneOf[T comparable](field string, value T, options []T) Rule
- func NoneOfString(field, value string, options []string) Rule
- func NotCommonPassword(field, value string) Rule
- func NotInList[T comparable](field string, value T, forbiddenValues []T) Rule
- func NotInListCaseInsensitive(field, value string, forbiddenValues []string) Rule
- func NotInListString(field, value string, forbiddenValues []string) Rule
- func OneOf[T comparable](field string, value T, options []T) Rule
- func OneOfString(field, value string, options []string) Rule
- func OnlyWhitespace(field, value string) Rule
- func PasswordDigit(field, value string) Rule
- func PasswordEntropy(field, value string, minEntropy float64) Rule
- func PasswordLowercase(field, value string) Rule
- func PasswordSpecialChar(field, value string) Rule
- func PasswordUppercase(field, value string) Rule
- func PastDate(field string, value time.Time) Rule
- func PositiveAmount[T Numeric](field string, value T) Rule
- func PrintableChars(field, value string) Rule
- func Required(field, value string) Rule
- func RequiredComparable[T comparable](field string, value T) Rule
- func RequiredMap[K comparable, V any](field string, value map[K]V) Rule
- func RequiredNum[T Numeric](field string, value T) Rule
- func RequiredSlice[T any](field string, value []T) Rule
- func RequiredString(field, value string) Rule
- func RequiredUUID(field string, value uuid.UUID) Rule
- func RequiredUUIDString(field, value string) Rule
- func StartsWithPattern(field, value string, pattern string) Rule
- func StrongPassword(field, value string, config PasswordStrengthConfig) Rule
- func TimeAfter(field string, value time.Time, after time.Time) Rule
- func TimeBefore(field string, value time.Time, before time.Time) Rule
- func TimeBetween(field string, value time.Time, start time.Time, end time.Time) Rule
- func ValidAPIKey(field, value string, minLength int, maxLength int) Rule
- func ValidAccountNumber(field, value string) Rule
- func ValidAlpha(field, value string) Rule
- func ValidAlphanumeric(field, value string) Rule
- func ValidBase64(field, value string) Rule
- func ValidBirthdate(field string, value time.Time) Rule
- func ValidCategory(field, value string, allowedCategories []string) Rule
- func ValidCreditCardChecksum(field, value string) Rule
- func ValidCurrencyCode(field, value string) Rule
- func ValidCustomID(field, value string, pattern string, description string) Rule
- func ValidDiscount(field string, value float64) Rule
- func ValidDomainName(field, value string) Rule
- func ValidEmail(field, value string) Rule
- func ValidEnum(field, value string, enumValues []string) Rule
- func ValidEnumCaseInsensitive(field, value string, enumValues []string) Rule
- func ValidHandle(field, value string, minLen int, maxLen int) Rule
- func ValidHexString(field, value string, exactLength int) Rule
- func ValidIP(field, value string) Rule
- func ValidIPv4(field, value string) Rule
- func ValidIPv6(field, value string) Rule
- func ValidInterestRate(field string, value float64, maxRate float64) Rule
- func ValidMAC(field, value string) Rule
- func ValidNumericString(field, value string) Rule
- func ValidOTP(field, value string, length int) Rule
- func ValidPercentage(field string, value float64) Rule
- func ValidPermission(field, value string, allowedPermissions []string) Rule
- func ValidPhone(field, value string) Rule
- func ValidProductCode(field, value string, pattern string) Rule
- func ValidRole(field, value string, allowedRoles []string) Rule
- func ValidRoutingNumber(field, value string) Rule
- func ValidSKU(field, value string) Rule
- func ValidSlug(field, value string) Rule
- func ValidSlugNotReserved(field, value string, reserved ...string) Rule
- func ValidStatus(field, value string, allowedStatuses []string) Rule
- func ValidSubdomain(field, value string) Rule
- func ValidTaxRate(field string, value float64) Rule
- func ValidTicketNumber(field, value string, prefix string) Rule
- func ValidURL(field, value string) Rule
- func ValidURLWithScheme(field, value string, schemes []string) Rule
- func ValidUUID(field, value string) Rule
- func ValidUUIDVersion(field string, value uuid.UUID, version int) Rule
- func ValidUUIDVersionString(field, value string, version int) Rule
- func ValidUUIDv1(field string, value uuid.UUID) Rule
- func ValidUUIDv1String(field, value string) Rule
- func ValidUUIDv3(field string, value uuid.UUID) Rule
- func ValidUUIDv3String(field, value string) Rule
- func ValidUUIDv4(field string, value uuid.UUID) Rule
- func ValidUUIDv4String(field, value string) Rule
- func ValidUUIDv5(field string, value uuid.UUID) Rule
- func ValidUUIDv5String(field, value string) Rule
- func ValidUsername(field, value string, minLen int, maxLen int) Rule
- func ValidVersion(field, value string) Rule
- func Weekend(field string, value time.Time) Rule
- func WordCount(field, value string, min int, max int) Rule
- func WorkingDay(field string, value time.Time) Rule
- type TranslateFunc
- type ValidationError
- type ValidationErrors
- func (ve *ValidationErrors) Add(err ValidationError)
- func (ve ValidationErrors) Error() string
- func (ve ValidationErrors) Fields() []string
- func (ve ValidationErrors) Get(field string) []string
- func (ve ValidationErrors) GetErrors(field string) []ValidationError
- func (ve ValidationErrors) Has(field string) bool
- func (ve ValidationErrors) IsEmpty() bool
- func (ve ValidationErrors) Translate(fn TranslateFunc)
- type ValidatorFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsValidationError ¶
func RegisterValidator ¶
func RegisterValidator(name string, fn ValidatorFunc)
RegisterValidator adds a custom validator function to the registry
func ValidateStruct ¶
ValidateStruct validates a struct based on its field tags
Types ¶
type PasswordStrengthConfig ¶
type PasswordStrengthConfig struct {
MinLength int
MaxLength int
RequireUppercase bool
RequireLowercase bool
RequireDigits bool
RequireSpecial bool
MinCharClasses int // Minimum number of different character classes required
}
func DefaultPasswordStrength ¶
func DefaultPasswordStrength() PasswordStrengthConfig
DefaultPasswordStrength returns NIST-recommended password policy: 8-128 chars, 3+ character classes.
type Rule ¶
type Rule struct {
Check func() bool
Error ValidationError
}
Rule represents a single validation rule.
func AmountRange ¶
func BalancedParentheses ¶
BalancedParentheses validates that parentheses in a string are balanced.
func BusinessHours ¶
func ContainsDigit ¶
ContainsDigit validates that a string contains at least one digit.
func ContainsLowercase ¶
ContainsLowercase validates that a string contains at least one lowercase letter.
func ContainsPattern ¶
ContainsPattern validates that a string contains a specific pattern.
func ContainsUppercase ¶
ContainsUppercase validates that a string contains at least one uppercase letter.
func CurrencyPrecision ¶
CurrencyPrecision enforces currency-specific decimal rules (USD=2, JPY=0, etc.).
func DateBetween ¶
func DecimalPrecision ¶
DecimalPrecision prevents floating-point precision issues in financial calculations.
func DoesNotMatchRegex ¶
func EndsWithPattern ¶
EndsWithPattern validates that a string ends with a specific pattern.
func InList ¶
func InList[T comparable](field string, value T, allowedValues []T) Rule
func InListCaseInsensitive ¶
func InListString ¶
func MatchesRegex ¶
MatchesRegex validates against custom patterns. Compiles regex on each call - cache externally for performance.
func MaxLenString ¶
func MaximumTransaction ¶
MaximumTransaction validates that a transaction amount doesn't exceed a maximum limit.
func MinAge ¶
MinAge validates minimum age by calculating years elapsed, accounting for leap years and exact dates.
func MinLenString ¶
func MinimumPurchase ¶
MinimumPurchase validates that a purchase amount meets a minimum threshold.
func NoControlChars ¶
NoControlChars validates that a string contains no control characters.
func NoRepeatingChars ¶
func NoSequentialChars ¶
NoSequentialChars prevents patterns like "abc" or "123" that reduce effective entropy.
func NoSpecialChars ¶
NoSpecialChars validates that a string contains no special characters (only letters, numbers, and spaces).
func NoWhitespace ¶
NoWhitespace validates that a string contains no whitespace characters.
func NonNegativeAmount ¶
func NonNilUUIDString ¶
func NoneOf ¶
func NoneOf[T comparable](field string, value T, options []T) Rule
func NoneOfString ¶
func NotCommonPassword ¶
func NotInList ¶
func NotInList[T comparable](field string, value T, forbiddenValues []T) Rule
func NotInListString ¶
func OneOf ¶
func OneOf[T comparable](field string, value T, options []T) Rule
func OneOfString ¶
func OnlyWhitespace ¶
OnlyWhitespace validates that a string contains only whitespace characters.
func PasswordDigit ¶
func PasswordEntropy ¶
PasswordEntropy validates password randomness using Shannon entropy. 50+ bits indicates strong randomness, 40-49 is moderate, <40 is weak.
func PasswordLowercase ¶
func PasswordSpecialChar ¶
func PasswordUppercase ¶
func PositiveAmount ¶
func PrintableChars ¶
PrintableChars validates that a string contains only printable characters.
func RequiredComparable ¶
func RequiredComparable[T comparable](field string, value T) Rule
func RequiredMap ¶
func RequiredMap[K comparable, V any](field string, value map[K]V) Rule
func RequiredNum ¶
func RequiredSlice ¶
func RequiredString ¶
RequiredString validates that a string is not empty after trimming whitespace.
func RequiredUUIDString ¶
func StartsWithPattern ¶
StartsWithPattern validates that a string starts with a specific pattern.
func StrongPassword ¶
func StrongPassword(field, value string, config PasswordStrengthConfig) Rule
func TimeBetween ¶
func ValidAPIKey ¶
ValidAPIKey validates that a string looks like a valid API key.
func ValidAccountNumber ¶
ValidAccountNumber validates that a bank account number is in a reasonable format. This is a basic validation - real implementations should use country-specific rules.
func ValidAlpha ¶
func ValidAlphanumeric ¶
func ValidBase64 ¶
ValidBase64 validates that a string is valid base64 encoding.
func ValidBirthdate ¶
ValidBirthdate ensures reasonable birthdate constraints: not future, not older than 150 years.
func ValidCategory ¶
func ValidCreditCardChecksum ¶
ValidCreditCardChecksum validates a credit card number using the Luhn algorithm.
func ValidCurrencyCode ¶
ValidCurrencyCode validates that a string is a valid ISO 4217 currency code.
func ValidCustomID ¶
ValidCustomID validates that a string matches a custom identifier pattern.
func ValidDiscount ¶
ValidDiscount validates that a discount percentage is reasonable (0-100%).
func ValidDomainName ¶
ValidDomainName validates that a string is a valid domain name.
func ValidEmail ¶
ValidEmail validates email addresses using RFC 5322 with additional web-friendly constraints. Rejects edge cases like quoted local parts and comments that are valid per RFC but problematic for web apps.
func ValidHandle ¶
ValidHandle validates that a string is a valid handle (starts with letter, then letters/numbers/underscore/hyphen).
func ValidHexString ¶
ValidHexString validates that a string contains only hexadecimal characters.
func ValidInterestRate ¶
ValidInterestRate validates that an interest rate is reasonable.
func ValidNumericString ¶
func ValidOTP ¶
ValidOTP validates that a string is a valid OTP code with the specified length. The OTP must contain exactly the specified number of digits (0-9 only).
func ValidPercentage ¶
ValidPercentage validates that a value is a valid percentage (0-100).
func ValidPermission ¶
func ValidPhone ¶
ValidPhone validates international phone numbers in E.164 format. Allows common formatting chars (spaces, dashes) but requires 7-15 digits total.
func ValidProductCode ¶
ValidProductCode validates that a string is a valid product code.
func ValidRoutingNumber ¶
ValidRoutingNumber validates that a routing number is in the correct format (US).
func ValidSlug ¶
ValidSlug validates URL-safe slugs, preventing edge cases like leading/trailing hyphens.
func ValidSlugNotReserved ¶
ValidSlugNotReserved validates URL-safe slugs and ensures they are not in the reserved list. The reserved slug check is case-insensitive.
func ValidStatus ¶
func ValidSubdomain ¶
ValidSubdomain validates that a string is a valid subdomain.
func ValidTaxRate ¶
ValidTaxRate validates that a tax rate is reasonable (0-100%).
func ValidTicketNumber ¶
ValidTicketNumber validates that a string is a valid ticket/reference number.
func ValidURLWithScheme ¶
func ValidUUID ¶
ValidUUID validates standard UUID format with pre-validation to avoid expensive parsing.
func ValidUUIDVersionString ¶
func ValidUUIDv1String ¶
func ValidUUIDv3String ¶
func ValidUUIDv4String ¶
func ValidUUIDv5String ¶
func ValidVersion ¶
ValidVersion validates that a string is a valid semantic version.
type TranslateFunc ¶
TranslateFunc translates a message key with the given values into a localized string.
type ValidationError ¶
type ValidationError struct {
TranslationValues map[string]any
Field string
Message string
TranslationKey string
}
ValidationError represents a single validation error with translation support.
type ValidationErrors ¶
type ValidationErrors []ValidationError
ValidationErrors represents a collection of validation errors.
func ExtractValidationErrors ¶
func ExtractValidationErrors(err error) ValidationErrors
ExtractValidationErrors extracts ValidationErrors from an error.
func (*ValidationErrors) Add ¶
func (ve *ValidationErrors) Add(err ValidationError)
func (ValidationErrors) Error ¶
func (ve ValidationErrors) Error() string
func (ValidationErrors) Fields ¶
func (ve ValidationErrors) Fields() []string
func (ValidationErrors) Get ¶
func (ve ValidationErrors) Get(field string) []string
func (ValidationErrors) GetErrors ¶
func (ve ValidationErrors) GetErrors(field string) []ValidationError
func (ValidationErrors) Has ¶
func (ve ValidationErrors) Has(field string) bool
func (ValidationErrors) IsEmpty ¶
func (ve ValidationErrors) IsEmpty() bool
func (ValidationErrors) Translate ¶
func (ve ValidationErrors) Translate(fn TranslateFunc)
Translate replaces the Message field of each ValidationError in-place using the provided translation function. Errors with an empty TranslationKey are skipped. It is a no-op if fn is nil or the slice is empty.