Skip to content

Releases: microbus-io/dv8

Compiled execution plans and tag introspection

Choose a tag to compare

@bw19 bw19 released this 11 Jul 17:06

Committed (24a5a6c). Release notes for v0.4.0:

Validation is now compiled once per type into a cached execution plan and executed as pre-bound closures, instead of re-parsing directive strings on every call. All operands are resolved at compile time: length and value bounds, defaults, oneof sets, and regular expressions (whose cache lock is gone from the hot path), while untagged fields and no-op containers are pruned from the plan entirely. Behavior is unchanged, including error messages, mutation ordering, and Validate-method dispatch, and Compile now also warms the plan cache. On a representative nested struct (Apple M1 Pro), Validate drops from 6350 ns and 103 allocations to 1273 ns and 17; a flat 4-field struct drops from 1010 ns and 15 allocations to 161 ns and zero. The release also exports ParseTag, which parses a dv8 tag into its directives without checking validity, enabling tooling such as an OpenAPI generator to project the directives onto other formats while keeping the tag grammar single-sourced.

Blame where blame is

Choose a tag to compare

@bw19 bw19 released this 11 Jul 15:49

This release makes dv8's errors self-attributing. Errors are now created with the microbus-io/errors package, dv8's first dependency, and carry an HTTP status code and a stack trace. A violation of the input data, such as a failed directive, a key-fold collision, or a rejection by a custom Validate method, is stamped 400 Bad Request, while a malformed directive, which is a bug in the struct tags rather than in the input, carries 500 Internal Server Error and continues to wrap dv8.ErrDirective for errors.Is matching. A custom Validate method may choose its own attribution by returning an error with any non-500 status code (e.g. errors.New("forbidden", http.StatusForbidden)), which dv8 respects; a plain error, or one carrying the default 500, is treated as a data rejection and stamped 400. Callers that route errors to HTTP responses can therefore propagate them as-is with errors.StatusCode(err) reading the code back, instead of branching on the error kind themselves. The status survives dv8's own field-path prefixing through nested structs, slices, and maps.

One `Validate` to rule them all

Choose a tag to compare

@bw19 bw19 released this 11 Jul 14:23

This release unifies dv8's API around a single name and makes the directive language explicit and strict. The dv8.ValidateContext entry point is removed: dv8.Validate now takes a context.Context as its first argument, with nil tolerated and treated as context.Background. The ValidatorContext interface is gone as well: Validator itself is now the context-taking interface, Validate(ctx context.Context) error, reaching any type in the object graph that implements it, while a parameterless Validate() error is honored as a fallback for types not written for dv8. Since Go forbids two same-named methods, the compiler enforces that a type implements at most one variant. The directive language is reworked for explicitness: directives on an array or map now apply to the container itself, the new each prefix distributes a directive to elements or map values, and the new key prefix applies directives to map keys, with mutated keys reinserted under their new value and two keys folding into one reported as an error. Consequently arrlen and maplen are retired in favor of plain len, and a nil container now has length 0, making notzero the nil check. required is renamed to notzero to say what it actually checks, main is renamed to delegate, and whitespace trimming is no longer applied by default, with notrim replaced by an opt-in trim. A comma inside a directive's value, such as a regexp quantifier, is now escaped with a backslash, written \\, in the tag, mirroring invopop/jsonschema. Directives are also strictly compiled once per type on first use: typos, misapplied directives, malformed operators or values, uncompilable regexps, and on targets that do not exist all fail with an error wrapping the new dv8.ErrDirective, which errors.Is distinguishes from invalid data, and the new dv8.Compile surfaces broken directives eagerly at startup before any data arrives. Compiled regular expressions are now cached, and a bug was fixed where a pointer-receiver context validator was silently skipped when the type did not also implement the parameterless variant. Upgrading from v0.2.x: pass a context (or nil) as the first argument of dv8.Validate, rename ValidateContext(ctx) methods to Validate(ctx), replace arrlen/maplen with len, prefix per-item directives with each, rename required to notzero and main to delegate, and add trim where trimming is desired. Note two silent behavior changes the strict compiler cannot catch: string fields that relied on implicit trimming, including required checks that counted on all-whitespace values being rejected, and container fields whose per-item rules now need an each prefix.

Copyrighter as a tool

Choose a tag to compare

@bw19 bw19 released this 18 Jun 20:30

Remove hard dependency on the copyrighter.

ValidatorContext interface

Choose a tag to compare

@bw19 bw19 released this 28 Jan 18:56

Added the option for structs to implement ValidateContext(ctx context.Context) error in addition to Validate() error

New directive "oneof"

Choose a tag to compare

@bw19 bw19 released this 07 Apr 23:16

A new directive to validate strings from a set of valid values: oneof A|B|C.
Call Validate on non-struct types as well.

Make the main Validate method variadic

Choose a tag to compare

@bw19 bw19 released this 31 Mar 23:02
v0.2.1

Variadic

Apply directives on array and map values

Choose a tag to compare

@bw19 bw19 released this 29 Mar 23:28

This release introduces a breaking change.
Directives placed on an array or map field now apply to the value elements of the array or map rather than to the array or map themselves.
New directives, "arrlen" and "maplen", were introduced to check the length of the array or map.

Correctly handle types that wrap a primitive type

Choose a tag to compare

@bw19 bw19 released this 24 Mar 21:44

Such as type MyEnum int

Better detection of Validator interface

Choose a tag to compare

@bw19 bw19 released this 24 Feb 03:04
v0.1.5

Merge branch 'main' of https://github.com/microbus-io/dv8