Options

Configuration options for validators

Complete reference for all configuration options (With* functions) available in the validation package.

Option Types

Options can be used in two ways:

  1. Validator Creation: Pass to New() or MustNew(). Applies to all validations.
  2. Per-Call: Pass to Validate() or ValidatePartial(). Applies to that call only.
// Validator creation options
validator := validation.MustNew(
    validation.WithMaxErrors(10),
    validation.WithRedactor(redactor),
)

// Per-call options (override validator config)
err := validator.Validate(ctx, &req,
    validation.WithMaxErrors(5), // Overrides the 10 from creation
    validation.WithStrategy(validation.StrategyTags),
)

Strategy Options

WithStrategy

func WithStrategy(strategy Strategy) Option

Sets the validation strategy to use.

Values:

  • StrategyAuto - Automatically select best strategy. This is the default.
  • StrategyTags - Use struct tags only.
  • StrategyJSONSchema - Use JSON Schema only.
  • StrategyInterface - Use interface methods only.

Example:

err := validation.Validate(ctx, &req,
    validation.WithStrategy(validation.StrategyTags),
)

WithRunAll

func WithRunAll(runAll bool) Option

Runs all applicable validation strategies and aggregates errors. By default, validation stops at the first successful strategy.

Example:

err := validation.Validate(ctx, &req,
    validation.WithRunAll(true),
)

WithRequireAny

func WithRequireAny(require bool) Option

When used with WithRunAll(true), succeeds if at least one strategy passes (OR logic).

Example:

// Pass if ANY strategy succeeds
err := validation.Validate(ctx, &req,
    validation.WithRunAll(true),
    validation.WithRequireAny(true),
)

Partial Validation Options

WithPartial

func WithPartial(partial bool) Option

Enables partial validation mode for PATCH requests. Validates only present fields and ignores “required” constraints for absent fields.

Example:

err := validation.Validate(ctx, &req,
    validation.WithPartial(true),
    validation.WithPresence(presenceMap),
)

WithPresence

func WithPresence(presence PresenceMap) Option

Sets the presence map for partial validation. Tracks which fields were provided in the request body.

Example:

presence, _ := validation.ComputePresence(rawJSON)
err := validation.Validate(ctx, &req,
    validation.WithPresence(presence),
    validation.WithPartial(true),
)

Error Limit Options

WithMaxErrors

func WithMaxErrors(maxErrors int) Option

Limits the number of errors returned. Set to 0 for unlimited errors (default).

Example:

// Return at most 5 errors
err := validation.Validate(ctx, &req,
    validation.WithMaxErrors(5),
)

var verr *validation.Error
if errors.As(err, &verr) {
    if verr.Truncated {
        fmt.Println("More errors exist")
    }
}

WithMaxFields

func WithMaxFields(maxFields int) Option

Sets the maximum number of fields to validate in partial mode. Prevents pathological inputs with extremely large presence maps. Set to 0 to use the default (10000).

Example:

validator := validation.MustNew(
    validation.WithMaxFields(5000),
)

Cache Options

WithMaxCachedSchemas

func WithMaxCachedSchemas(maxCachedSchemas int) Option

Sets the maximum number of JSON schemas to cache. Uses LRU eviction when limit is reached. Set to 0 to use the default (1024).

Example:

validator := validation.MustNew(
    validation.WithMaxCachedSchemas(2048),
)

Security Options

WithRedactor

func WithRedactor(redactor Redactor) Option

Sets a redactor function to hide sensitive values in error messages. The redactor returns true if the field at the given path should be redacted.

Example:

redactor := func(path string) bool {
    return strings.Contains(path, "password") ||
           strings.Contains(path, "token") ||
           strings.Contains(path, "secret")
}

validator := validation.MustNew(
    validation.WithRedactor(redactor),
)

WithDisallowUnknownFields

func WithDisallowUnknownFields(disallow bool) Option

Rejects JSON with unknown fields (typo detection). When enabled, causes strict JSON binding to reject requests with fields not defined in the struct.

Example:

err := validation.Validate(ctx, &req,
    validation.WithDisallowUnknownFields(true),
)

Context Options

WithContext

func WithContext(ctx context.Context) Option

Overrides the context used for validation. Useful when you need a different context than the one passed to Validate().

Note: In most cases, you should pass the context directly to Validate(). This option exists for advanced use cases.

Example:

err := validator.Validate(requestCtx, &req,
    validation.WithContext(backgroundCtx),
)

Custom Validation Options

WithCustomSchema

func WithCustomSchema(id, schema string) Option

Sets a custom JSON Schema for validation. This overrides any schema provided by the JSONSchemaProvider interface.

Example:

customSchema := `{
    "type": "object",
    "properties": {
        "email": {"type": "string", "format": "email"}
    }
}`

err := validation.Validate(ctx, &req,
    validation.WithCustomSchema("custom-user", customSchema),
)

WithCustomValidator

func WithCustomValidator(fn func(any) error) Option

Sets a custom validation function that runs before any other validation strategies.

Example:

err := validation.Validate(ctx, &req,
    validation.WithCustomValidator(func(v any) error {
        req := v.(*UserRequest)
        if req.Age < 18 {
            return errors.New("must be 18 or older")
        }
        return nil
    }),
)

WithCustomTag

func WithCustomTag(name string, fn validator.Func) Option

Registers a custom validation tag for use in struct tags. Custom tags are registered when the validator is created.

Example:

phoneValidator := func(fl validator.FieldLevel) bool {
    return phoneRegex.MatchString(fl.Field().String())
}

validator := validation.MustNew(
    validation.WithCustomTag("phone", phoneValidator),
)

type User struct {
    Phone string `validate:"phone"`
}

Error Message Options

WithMessages

func WithMessages(messages map[string]string) Option

Sets static error messages for validation tags. Messages override the default English messages for specified tags.

Example:

validator := validation.MustNew(
    validation.WithMessages(map[string]string{
        "required": "cannot be empty",
        "email":    "invalid email format",
        "min":      "value too small",
    }),
)

WithMessageFunc

func WithMessageFunc(tag string, fn MessageFunc) Option

Sets a dynamic message generator for a parameterized tag. Use for tags like “min”, “max”, “len” that include parameters.

Example:

minMessage := func(param string, kind reflect.Kind) string {
    if kind == reflect.String {
        return fmt.Sprintf("must be at least %s characters", param)
    }
    return fmt.Sprintf("must be at least %s", param)
}

validator := validation.MustNew(
    validation.WithMessageFunc("min", minMessage),
)

Field Name Options

WithFieldNameMapper

func WithFieldNameMapper(mapper func(string) string) Option

Sets a function to transform field names in error messages. Useful for localization or custom naming conventions.

Example:

validator := validation.MustNew(
    validation.WithFieldNameMapper(func(name string) string {
        // Convert snake_case to Title Case
        return strings.Title(strings.ReplaceAll(name, "_", " "))
    }),
)

Options Summary

Validator Creation Options

Options that should be set when creating a validator (affect all validations):

OptionPurpose
WithMaxErrorsLimit total errors returned
WithMaxFieldsLimit fields in partial validation
WithMaxCachedSchemasSchema cache size
WithRedactorRedact sensitive fields
WithCustomTagRegister custom validation tag
WithMessagesCustom error messages
WithMessageFuncDynamic error messages
WithFieldNameMapperTransform field names

Per-Call Options

Options commonly used per-call (override validator config):

OptionPurpose
WithStrategyChoose validation strategy
WithRunAllRun all strategies
WithRequireAnyOR logic with WithRunAll
WithPartialEnable partial validation
WithPresenceSet presence map
WithMaxErrorsOverride error limit
WithCustomValidatorAdd custom validator
WithCustomSchemaOverride JSON Schema
WithDisallowUnknownFieldsReject unknown fields
WithContextOverride context

Usage Patterns

Creating Configured Validator

validator := validation.MustNew(
    // Security
    validation.WithRedactor(sensitiveRedactor),
    validation.WithMaxErrors(20),
    validation.WithMaxFields(5000),
    
    // Custom validation
    validation.WithCustomTag("phone", phoneValidator),
    validation.WithCustomTag("username", usernameValidator),
    
    // Error messages
    validation.WithMessages(map[string]string{
        "required": "is required",
        "email":    "must be a valid email",
    }),
)

Per-Call Overrides

// Use tags strategy only
err := validator.Validate(ctx, &req,
    validation.WithStrategy(validation.StrategyTags),
    validation.WithMaxErrors(5),
)

// Partial validation
err := validator.Validate(ctx, &req,
    validation.WithPartial(true),
    validation.WithPresence(presence),
)

// Custom validation
err := validator.Validate(ctx, &req,
    validation.WithCustomValidator(complexBusinessLogic),
)

Next Steps