• v1.0.0 ab11fd2ace

    Rene Nochebuena released this 2026-05-11 18:21:29 -06:00 | 1 commits to main since this release

    v1.0.0

    code.nochebuena.dev/go/valid

    Overview

    valid v1.0.0 commits the struct validation API as stable. All v0.9.0 roadmap
    items are resolved. The module ships a minimal Validator interface backed by
    go-playground/validator/v10, fully decoupled from the public surface, with
    pluggable i18n via MessageProvider and tight xerrors integration.

    What Changed Since v0.9.0

    New: JSON tag name resolution

    Field names in error context now use the json struct tag when available,
    falling back to the Go field name if no tag is defined or the tag is "-".

    Before (v0.9.0):

    // struct field: EmailAddress string `json:"email_address" validate:"required"`
    xe.Fields()["field"] // → "EmailAddress"
    

    After (v1.0.0):

    xe.Fields()["field"] // → "email_address"
    

    The same name is passed to MessageProvider.Message(field, tag, param), so
    custom providers automatically receive the JSON-facing field name.

    Structs without json tags are unaffected — the Go field name continues to be used.

    Roadmap items resolved

    Item Resolution
    Surfacing all validation errors No — Unwrap() exposes playground.ValidationErrors for callers that need all failures
    JSON tag name resolution Implemented via RegisterTagNameFunc
    Feedback on MessageProvider interface Stable — Message(field, tag, param string) string committed
    Cross-field validation helpers No — no recurring need identified from consumer codebases

    Full API (stable)

    Validator — interface with a single method: Struct(v any) error.
    Returns nil if valid, *xerrors.Err with ErrInvalidInput for field failures
    (first failing field), or *xerrors.Err with ErrInternal for non-struct input.

    New(opts ...Option) Validator — constructor. Uses DefaultMessages (English) unless overridden.

    WithMessageProvider(mp MessageProvider) Option — functional option to inject a custom message provider.

    MessageProvider — interface: Message(field, tag, param string) string.
    field is the json tag name when available, otherwise the Go field name.

    DefaultMessages — built-in English provider for required, email, min, max, and a generic fallback.

    SpanishMessages — opt-in Spanish provider for the same tag set.

    Migration from v0.9.0

    No breaking changes to the API surface. The only behavioral change is field
    name resolution: if your structs define json tags, the "field" key in
    error context and the field argument to MessageProvider.Message will now
    reflect the json tag name instead of the Go field name.

    go get code.nochebuena.dev/go/valid@v1.0.0
    
    Downloads
  • v0.9.0 328b80c060

    Rene Nochebuena released this 2026-03-18 15:03:13 -06:00 | 2 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