Part of #267 — Phase 2.
Goal
Add github.com/go-playground/validator/v10 and consolidate scattered post-decode checks into declarative validate: tags.
Current state
decodeJSONStrict() is good. But after decode, each handler has inline checks: if testType == "" { testType = "throughput" }, interface existence checks, mode-switch preconditions. These are inconsistent and produce inconsistent error responses.
Acceptance criteria
Notes
Coordinate the error response shape with seed's parallel validator work (krisarmstrong/seed) so the two repos return the same JSON error envelope.
Part of #267 — Phase 2.
Goal
Add
github.com/go-playground/validator/v10and consolidate scattered post-decode checks into declarativevalidate:tags.Current state
decodeJSONStrict()is good. But after decode, each handler has inline checks:if testType == "" { testType = "throughput" }, interface existence checks, mode-switch preconditions. These are inconsistent and produce inconsistent error responses.Acceptance criteria
github.com/go-playground/validator/v10added togo.mod(pin exact version)internal/api/validator.govalidate:tags on DTOs in:handlers_auth.go,handlers_license.go,handlers_recovery.go,handlers_settings.go,handlers_mode.govalidateStruct(w, v) boolwrites 400 with structured field errorsStructLevelFunctestType = "throughput") moved out of validation into an explicit default-fill step (don't conflate "valid" with "defaulted")//nolintsuppressionNotes
Coordinate the error response shape with seed's parallel validator work (
krisarmstrong/seed) so the two repos return the same JSON error envelope.