validation

package
v0.0.0-...-927d699 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package validation provides a programmatic, type-safe validation engine using Go generics.

Overview

Validation in Credo uses generic Rule interfaces and pointer-based field references for compile-time type safety. No struct tags are used for rule definition. Reflection is limited to field name extraction (cached after first use per struct type).

Quick Start

import v "github.com/credo-go/credo/validation"

type CreateUserInput struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

func (c *CreateUserInput) Validate() error {
    return v.ValidateStruct(c,
        v.Field(&c.Name, v.Required[string](), v.Length(2, 100)),
        v.Field(&c.Email, v.Required[string](), v.Email()),
        v.Field(&c.Age, v.Required[int](), v.Min(18)),
    )
}

When the struct implements Validatable, the Validate method is called automatically by BindBody and BindQuery. In debug mode, a warning is logged if the target does not implement Validatable.

Error Format

Validation errors are returned as Errors ([]ValidationError), designed for RFC 7807 Problem Details integration. Each error includes Field, Code, Message, and optional Params for i18n template rendering.

PATCH Support

For partial updates with pointer fields, use NilSafe:

v.Field(&u.Name, v.NilSafe(v.Length(2, 100)))

Adapted From

API design adapted from ozzo-validation (MIT). Generic Rule architecture inspired by govy (design only, no code adapted). See NOTICES file for full attribution.

Maturity: experimental

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidateStruct

func ValidateStruct(structPtr any, fields ...FieldRules) error

ValidateStruct validates a struct by running all field rules. Returns nil if all validations pass, or Errors containing all failures.

structPtr must be a non-nil pointer to a struct. Passing a nil pointer returns nil (valid). Passing a non-pointer or pointer to non-struct panics.

Types

type Errors

type Errors []ValidationError

Errors is a collection of validation errors. It implements the error interface and json.Marshaler for RFC 7807 integration.

func (Errors) Error

func (e Errors) Error() string

Error implements the error interface. Returns a semicolon-separated summary.

func (Errors) MarshalJSON

func (e Errors) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler. Serializes as a JSON array.

func (Errors) Unwrap

func (e Errors) Unwrap() []error

Unwrap returns the individual field errors, letting errors.As (and errors.Is) descend from a validation result — possibly wrapped further up the call chain — down to single *ValidationError values.

type FieldRules

type FieldRules interface {
	// contains filtered or unexported methods
}

FieldRules is a type-erased container returned by Field. The unexported methods prevent external implementation — only Field can produce values satisfying this interface.

func Field

func Field[T any](fieldPtr *T, rules ...Rule[T]) FieldRules

Field creates a FieldRules that validates the struct field pointed to by fieldPtr using the given rules. The type parameter T is inferred from fieldPtr.

When fieldPtr points to a field that implements Validatable and no explicit rules are given, Validate() is called automatically (nested struct support).

type Rule

type Rule[T any] interface {
	Validate(value T) error
}

Rule is the generic validation rule interface. The type parameter T matches the field type, providing compile-time type safety.

func AllowedExtensions

func AllowedExtensions(exts ...string) Rule[*multipart.FileHeader]

AllowedExtensions creates a Rule that restricts the uploaded file's extension (taken from multipart.FileHeader.Filename) to the given list. Extensions are compared case-insensitively, and a leading dot is optional in the allow-list — "jpg" and ".jpg" are equivalent. A file whose name has no extension fails unless "" is explicitly allowed. A nil file header passes — use Required to enforce presence.

func AllowedMimeTypes

func AllowedMimeTypes(types ...string) Rule[*multipart.FileHeader]

AllowedMimeTypes creates a Rule that restricts the uploaded file's declared MIME type to the given list. The MIME type is read from the part's Content-Type header, which is client-supplied and therefore not authoritative — pair it with content sniffing (e.g. http.DetectContentType) when stronger guarantees are needed. Comparison is case-insensitive and ignores media-type parameters such as "; charset=utf-8". A nil file header passes — use Required to enforce presence.

func Between

func Between[T cmp.Ordered](min, max T) Rule[T]

Between creates a Rule that validates the value is between min and max (inclusive).

func By

func By[T any](fn func(T) error) Rule[T]

By creates a Rule from an inline function. The type parameter T is inferred from the function signature.

validation.Field(&c.Code, validation.By(func(code string) error {
    if len(code) != 2 {
        return errors.New("must be a 2-letter code")
    }
    return nil
}))

func DateAfter

func DateAfter(threshold time.Time) Rule[time.Time]

DateAfter creates a Rule that validates the time is after the given threshold. Zero time passes validation — use Required to enforce non-zero.

func DateBefore

func DateBefore(threshold time.Time) Rule[time.Time]

DateBefore creates a Rule that validates the time is before the given threshold. Zero time passes validation — use Required to enforce non-zero.

func Each

func Each[T any](rules ...Rule[T]) Rule[[]T]

Each creates a Rule that validates each element of a slice against the given rules. Error fields use bracket notation: "[0]", "[1]", etc.

func Email

func Email() Rule[string]

Email creates a Rule that validates email format. Empty strings pass validation — use Required to enforce non-empty.

func In

func In[T comparable](values ...T) Rule[T]

In creates a Rule that checks the value is one of the allowed values. The allowed values are not included in the error message for security.

func Length

func Length(min, max int) Rule[string]

Length creates a Rule that validates string length (rune count) is between min and max (inclusive). Uses utf8.RuneCountInString for correct Unicode handling. Empty strings pass validation — use Required to enforce non-empty.

func Max

func Max[T cmp.Ordered](threshold T) Rule[T]

Max creates a Rule that validates the value is <= threshold.

func MaxFileSize

func MaxFileSize(maxBytes int64) Rule[*multipart.FileHeader]

MaxFileSize creates a Rule that fails if the uploaded file is larger than maxBytes. The size is read from multipart.FileHeader.Size, which the multipart parser fills in from the request. A nil file header passes — use Required to enforce presence.

func Min

func Min[T cmp.Ordered](threshold T) Rule[T]

Min creates a Rule that validates the value is >= threshold.

func NilSafe

func NilSafe[T any](rules ...Rule[T]) Rule[*T]

NilSafe wraps rules for use with pointer fields. When the pointer is nil, validation is skipped. When non-nil, the value is dereferenced and inner rules execute. Used for PATCH/partial update support.

type UpdateUserInput struct {
    Name *string `json:"name"`
}

validation.Field(&u.Name, validation.NilSafe(validation.Length(2, 100)))

func NotEmptyMap

func NotEmptyMap[K comparable, V any]() Rule[map[K]V]

NotEmptyMap creates a Rule that fails when the map has no entries (nil or zero length). It is the map counterpart of Required, whose comparable constraint excludes maps; the check is len-based — no reflection.

validation.Field(&c.Limits, validation.NotEmptyMap[string, int]())

func NotEmptySlice

func NotEmptySlice[E any]() Rule[[]E]

NotEmptySlice creates a Rule that fails when the slice has no elements (nil or zero length). It is the slice counterpart of Required, whose comparable constraint excludes slices; the check is len-based — no reflection.

validation.Field(&o.Items, validation.NotEmptySlice[Item]())

func NotNil

func NotNil[T any]() Rule[*T]

NotNil creates a Rule that checks the pointer is not nil.

func Regex

func Regex(pattern *regexp.Regexp) Rule[string]

Regex creates a Rule that validates the value matches the given pattern. The pattern must be pre-compiled via regexp.MustCompile or regexp.Compile. Empty strings pass validation — use Required to enforce non-empty. Panics if pattern is nil — a nil pattern is a programming error, never a runtime condition.

func Required

func Required[T comparable]() Rule[T]

Required creates a Rule that fails if the value is the zero value for type T. Works with any comparable type: strings, ints, bools, etc.

func URL

func URL() Rule[string]

URL creates a Rule that validates URL format. The URL must have both a scheme and a host. Empty strings pass validation — use Required to enforce non-empty.

func UUID

func UUID() Rule[string]

UUID creates a Rule that validates UUID format. Accepts both hyphenated (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) and plain (xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) formats. Empty strings pass validation — use Required to enforce non-empty.

func When

func When[T any](condition bool, rules ...Rule[T]) Rule[T]

When creates a Rule that conditionally applies rules based on a boolean condition. When the condition is false, validation is skipped (returns nil). When true, all inner rules are executed and errors are collected.

validation.Field(&o.CardNumber,
    validation.When(o.PaymentMethod == "card",
        validation.Required[string](), validation.Length(13, 19),
    ),
)

type Validatable

type Validatable interface {
	Validate() error
}

Validatable is implemented by types that can validate themselves. When a target struct implements Validatable, the Bind methods (BindBody, BindQuery) automatically call Validate() after decoding ("parse, don't validate").

Nested struct fields that implement Validatable are auto-validated by Field when no explicit rules are given.

type ValidationError

type ValidationError struct {
	// Field is the field path, e.g. "name", "address.city", "items[0]".
	Field string `json:"field"`

	// Code is the rule identifier / i18n key, e.g. "required", "email", "min".
	Code string `json:"code"`

	// Message is the default English error message.
	Message string `json:"message"`

	// Params holds template variables for localized messages,
	// e.g. {"min": 2, "max": 100}.
	//
	// Params is serialized into the HTTP error response (deliberately —
	// clients use it to render localized messages). Custom rules must not
	// place internal or sensitive values here.
	Params map[string]any `json:"params,omitempty"`
}

ValidationError represents a single field validation failure.

func (*ValidationError) Error

func (e *ValidationError) Error() string

Error implements the error interface.

Jump to

Keyboard shortcuts

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