Validation Package
5 minute read
This is the API reference for the rivaas.dev/validation package. For learning-focused documentation, see the Validation Guide.
Package Information
- Import Path:
rivaas.dev/validation - Go Version: 1.25+
- Documentation: pkg.go.dev/rivaas.dev/validation
- Repository: github.com/rivaas-dev/rivaas
Overview
The validation package provides flexible validation for Go structs with support for multiple strategies: struct tags, JSON Schema, and custom interfaces. It’s designed for web applications with features like partial validation for PATCH requests, sensitive data redaction, and detailed error reporting.
import "rivaas.dev/validation"
type User struct {
Email string `validate:"required,email"`
Age int `validate:"min=18"`
}
err := validation.Validate(ctx, &user)
Key Features
- Multiple Validation Strategies: Struct tags, JSON Schema, custom interfaces
- Partial Validation: PATCH request support with presence tracking
- Thread-Safe: Safe for concurrent use
- Security: Built-in redaction, nesting limits, memory protection
- Structured Errors: Field-level errors with codes and metadata
- Extensible: Custom tags, validators, and error messages
Package Architecture
graph TB
User[User Code] --> API[Public API]:::info
API --> Validate[Validate Functions]
API --> Validator[Validator Type]
API --> Presence[Presence Tracking]
Validate --> Strategy[Strategy Selection]:::warning
Validator --> Strategy
Strategy --> Tags[Struct Tags]
Strategy --> Schema[JSON Schema]
Strategy --> Interface[Custom Interfaces]
Tags --> Errors[Error Collection]
Schema --> Errors
Interface --> Errors
Errors --> ErrorType[Error/FieldError]:::danger
Presence --> Partial[Partial Validation]
Partial --> Strategy
classDef default fill:#F8FAF9,stroke:#1E6F5C,color:#1F2A27
classDef info fill:#D1ECF1,stroke:#17A2B8,color:#1F2A27
classDef warning fill:#FFF3CD,stroke:#FFC107,color:#1F2A27
classDef danger fill:#F8D7DA,stroke:#DC3545,color:#1F2A27Quick Navigation
Core types, functions, and validation methods.
Configuration options and validator settings.
Custom validation interfaces and providers.
Validation strategy selection and priority.
Common validation issues and solutions.
Step-by-step tutorials and examples.
Core API
Package-Level Functions
Simple validation without creating a validator instance:
// Validate with default configuration
func Validate(ctx context.Context, v any, opts ...Option) error
// Validate only present fields (PATCH requests)
func ValidatePartial(ctx context.Context, v any, pm PresenceMap, opts ...Option) error
// Compute which fields are present in JSON
func ComputePresence(rawJSON []byte) (PresenceMap, error)
Validator Type
Create configured validator instances for reuse:
// Create validator (returns error on invalid config)
func New(opts ...Option) (*Validator, error)
// Create validator (panics on invalid config)
func MustNew(opts ...Option) *Validator
// Validator methods
func (v *Validator) Validate(ctx context.Context, val any, opts ...Option) error
func (v *Validator) ValidatePartial(ctx context.Context, val any, pm PresenceMap, opts ...Option) error
Error Types
Structured validation errors:
// Main error type with multiple field errors
type Error struct {
Fields []FieldError
Truncated bool
}
// Individual field error
type FieldError struct {
Path string // JSON path (e.g., "items.2.price")
Code string // Error code (e.g., "tag.required")
Message string // Human-readable message
Meta map[string]any // Additional metadata
}
Interfaces
Implement these for custom validation:
// Simple custom validation
type ValidatorInterface interface {
Validate() error
}
// Context-aware custom validation
type ValidatorWithContext interface {
ValidateContext(context.Context) error
}
// JSON Schema provider
type JSONSchemaProvider interface {
JSONSchema() (id, schema string)
}
// Redactor for sensitive fields
type Redactor func(path string) bool
Validation Strategies
The package supports three strategies with automatic selection:
Priority Order:
- Interface methods (
Validate()/ValidateContext()) - Struct tags (
validate:"...") - JSON Schema (
JSONSchemaProvider)
// Automatic strategy selection
err := validation.Validate(ctx, &user)
// Explicit strategy
err := validation.Validate(ctx, &user,
validation.WithStrategy(validation.StrategyTags),
)
// Run all strategies
err := validation.Validate(ctx, &user,
validation.WithRunAll(true),
)
Configuration Options
Validator Creation Options
validator := validation.MustNew(
validation.WithMaxErrors(10), // Limit errors returned
validation.WithMaxCachedSchemas(2048), // Schema cache size
validation.WithRedactor(redactorFunc), // Redact sensitive fields
validation.WithCustomTag("phone", phoneValidator), // Custom tag
validation.WithMessages(messageMap), // Custom error messages
validation.WithMessageFunc("min", minFunc), // Dynamic messages
)
Per-Call Options
err := validator.Validate(ctx, &user,
validation.WithStrategy(validation.StrategyTags),
validation.WithPartial(true),
validation.WithPresence(presenceMap),
validation.WithMaxErrors(5),
validation.WithCustomValidator(customFunc),
)
Usage Patterns
Basic Validation
type User struct {
Email string `validate:"required,email"`
Age int `validate:"min=18"`
}
user := User{Email: "test@example.com", Age: 25}
if err := validation.Validate(ctx, &user); err != nil {
var verr *validation.Error
if errors.As(err, &verr) {
for _, fieldErr := range verr.Fields {
fmt.Printf("%s: %s\n", fieldErr.Path, fieldErr.Message)
}
}
}
Partial Validation (PATCH)
rawJSON := []byte(`{"email": "new@example.com"}`)
presence, _ := validation.ComputePresence(rawJSON)
var req UpdateUserRequest
json.Unmarshal(rawJSON, &req)
err := validation.ValidatePartial(ctx, &req, presence)
Custom Validator
validator := validation.MustNew(
validation.WithCustomTag("phone", func(fl validator.FieldLevel) bool {
return phoneRegex.MatchString(fl.Field().String())
}),
validation.WithRedactor(func(path string) bool {
return strings.Contains(path, "password")
}),
)
err := validator.Validate(ctx, &user)
Performance Characteristics
- First validation: ~500ns overhead for reflection
- Subsequent validations: ~50ns overhead (cache lookup)
- Schema caching: LRU with configurable size (default 1024)
- Thread-safe: All operations safe for concurrent use
- Zero allocation: Field paths cached per type
Integration
With net/http
func Handler(w http.ResponseWriter, r *http.Request) {
var req CreateUserRequest
json.NewDecoder(r.Body).Decode(&req)
if err := validation.Validate(r.Context(), &req); err != nil {
http.Error(w, err.Error(), http.StatusUnprocessableEntity)
return
}
// Process request
}
With rivaas.dev/router
func Handler(c *router.Context) error {
var req CreateUserRequest
c.BindJSON(&req)
if err := validation.Validate(c.Request().Context(), &req); err != nil {
return c.JSON(http.StatusUnprocessableEntity, err)
}
return c.JSON(http.StatusOK, processRequest(req))
}
With rivaas.dev/app
func Handler(c *app.Context) error {
var req CreateUserRequest
if err := c.Bind(&req); err != nil {
return err // Automatically validated and handled
}
return c.JSON(http.StatusOK, processRequest(req))
}
Version Compatibility
The validation package follows semantic versioning:
- v1.x: Stable API, backward compatible
- v2.x: Major changes, may require code updates
External Links
See Also
- rivaas.dev/binding - Request data binding
- rivaas.dev/router - HTTP routing
- rivaas.dev/app - Application framework
- go-playground/validator - Underlying struct tag validator
For step-by-step guides and tutorials, see the Validation Guide.
For real-world examples, see the Examples page.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.