No struct-level validation (wire fields by hand) #4

Open
opened 2026-09-07 12:22:50 +00:00 by claude · 1 comment
Member

validator/v10 and ozzo-validation both let you validate a whole struct in one call — validate:"required,email" tags, or ValidateStruct(&s, Field(&s.Email, Required, Email)). This package has no equivalent: you call each field validator yourself and combine the results by hand.

For a small struct that's fine and arguably clearer. For a 20-field API payload it's a lot of boilerplate, and there's no standard way to attach a field name to each error.

Not proposing a fix yet — this is the one gap that pulls the package toward either reflection or a much larger API surface, so it needs a design decision first. Options on the table:

  • Field + Fields helpers, no reflection. Field[T](name string, value T, fs ...func(T) error) error returns an error tagged with the field name; Fields(...error) error aggregates. Caller repeats the field name once. Keeps the no-magic property.
  • ozzo-style Struct(&s, ...) using pointer identity (or reflection) to recover field names from &s.Field. Nicer call site, but reintroduces reflection.
  • Do nothing in code, document the manual pattern (a map[string]error built by the caller) in the README.

Depends on the aggregation decision in #5 too — field validation wants all errors, not fail-fast.

`validator/v10` and `ozzo-validation` both let you validate a whole struct in one call — `validate:"required,email"` tags, or `ValidateStruct(&s, Field(&s.Email, Required, Email))`. This package has no equivalent: you call each field validator yourself and combine the results by hand. For a small struct that's fine and arguably clearer. For a 20-field API payload it's a lot of boilerplate, and there's no standard way to attach a field name to each error. **Not proposing a fix yet** — this is the one gap that pulls the package toward either reflection or a much larger API surface, so it needs a design decision first. Options on the table: - **`Field` + `Fields` helpers, no reflection.** `Field[T](name string, value T, fs ...func(T) error) error` returns an error tagged with the field name; `Fields(...error) error` aggregates. Caller repeats the field name once. Keeps the no-magic property. - **ozzo-style `Struct(&s, ...)`** using pointer identity (or reflection) to recover field names from `&s.Field`. Nicer call site, but reintroduces reflection. - **Do nothing in code**, document the manual pattern (a `map[string]error` built by the caller) in the README. Depends on the aggregation decision in #5 too — field validation wants all errors, not fail-fast.
Owner

@claude Ignore this issue unless I draw your attention to it again in the future. I have no intention of changing this right now, but I want to keep the issue open for future reference.

@claude Ignore this issue unless I draw your attention to it again in the future. I have no intention of changing this right now, but I want to keep the issue open for future reference.
aneurin added the wontfix label 2026-09-07 16:34:37 +00:00
Sign in to join this conversation.