• v0.9.0 328b80c060

    Rene Nochebuena released this 2026-03-18 15:03:13 -06:00 | 0 commits to main since this release

    v0.9.0

    code.nochebuena.dev/go/valid

    Overview

    valid is a struct validation module backed by github.com/go-playground/validator/v10. It
    exposes a minimal Validator interface and translates playground error types into
    *xerrors.Err values with stable Code values, so higher-tier middleware can map validation
    failures to HTTP status codes without coupling to the underlying library.

    This is the first stable release. The API was designed through multiple architecture reviews
    and validated end-to-end via the todo-api proof-of-concept. It is versioned at v0.9.0 rather
    than v1.0.0 because the library has not yet been exercised in production across all edge cases;
    the pre-1.0 version preserves the option for minor API refinements without a major bump.

    What's Included

    • Validator interface with a single Struct(v any) error method
    • New(...Option) Validator constructor; uses DefaultMessages (English) unless overridden
    • WithMessageProvider(mp MessageProvider) Option functional option for i18n
    • MessageProvider interface: Message(field, tag, param string) string
    • DefaultMessages — built-in English provider (required, email, min, max, and a generic fallback)
    • SpanishMessages — opt-in Spanish provider covering the same tag set
    • Error integration with xerrors:
      • ValidationErrors (field constraint failure) → xerrors.ErrInvalidInput with "field" and "tag" context keys
      • InvalidValidationError (non-struct argument) → xerrors.ErrInternal
      • Full playground.ValidationErrors attached via WithError for callers that need all failures

    Installation

    go get code.nochebuena.dev/go/valid@v0.9.0
    

    Requires Go 1.21 or later. Depends on code.nochebuena.dev/go/xerrors.

    Design Highlights

    Backend is hidden. *playground.Validate is never part of the public API. Callers
    interact only with Validator and *xerrors.Err; swapping or upgrading the backend does not
    change the public surface.

    Stable error codes. Validation failures always carry xerrors.ErrInvalidInput. HTTP
    middleware can convert that code to 422 without parsing error messages.

    Pluggable i18n. MessageProvider is a one-method interface. Implement it to supply
    messages in any language or to pull strings from a translation catalog.

    Structured context on errors.

    var xe *xerrors.Err
    if errors.As(err, &xe) {
        field := xe.Fields()["field"] // e.g. "Email"
        tag   := xe.Fields()["tag"]   // e.g. "email"
    }
    

    Known Limitations & Edge Cases

    • Only the first validation error is surfaced. Struct returns a single *xerrors.Err.
      Callers that need all failing fields must unwrap the attached playground.ValidationErrors
      manually via errors.As.
    • Field name is the Go struct field name, not the JSON tag. If the struct field is
      EmailAddress but the JSON key is email_address, the error context shows EmailAddress.
    • No cross-field validation helpers. The MessageProvider interface receives individual
      field/tag/param tuples; there is no built-in mechanism for messages that reference multiple
      fields.
    • No custom tag registration API. Callers cannot register custom validation tags through
      this module's public surface without casting to the underlying type.

    v0.9.0 → v1.0.0 Roadmap

    • Evaluate surfacing all validation errors (not just the first) as a structured slice, either
      via a new method or an option.
    • Investigate whether JSON tag names can be resolved automatically for the "field" context key.
    • Gather production feedback on the MessageProvider interface signature before committing to it.
    • Add cross-field validation helpers if a recurring need emerges from consumer codebases.
    Downloads