# Go Validate Small, composable value validators for Go. A validator is just a `func(T) error` — it returns `nil` or an error. You compose them with `All` or `Collect` and drop in plain closures wherever you need something custom. No struct tags, no reflection, no dependencies outside the standard library. ```go username := validate.All( validate.MinLength(3), validate.MaxLength(16), validate.Chars("abcdefghijklmnopqrstuvwxyz0123456789_"), func(s string) error { if strings.HasPrefix(s, "_") { return errors.New("must not start with an underscore") } return nil }, ) if err := username(input); err != nil { // errors.Is(err, validate.ErrDisallowedChars) still works } ``` ## Why this and not one of the established packages | Package | Style | |---|---| | [`go-playground/validator`](https://github.com/go-playground/validator) | struct tags (`validate:"required,email"`) driven by reflection | | [`go-ozzo/ozzo-validation`](https://github.com/go-ozzo/ozzo-validation) | rules composed in code, through a `Rule` interface over `interface{}` | | [`asaskevich/govalidator`](https://github.com/asaskevich/govalidator) | a bag of `IsEmail` / `IsURL` string helpers | This package is the code-composition style (closest to ozzo-validation) with two constraints held on purpose: - **Validators are ordinary generic functions.** `In`, `Equal` and the rest are type-checked by the compiler — pass the wrong type and it does not build. The tag/reflection libraries can't do this; they predate generics. - **Errors are plain sentinels.** `errors.Is(err, ErrInvalidEmail)` composes with the standard `errors` package. There is no bespoke `ValidationErrors` type to learn. `Err` matches any error from the package. Everything is value-level: there is no struct walker. You wire fields together yourself (a few lines) and decide how to present the result. ## Fail fast or collect everything ```go // stops at the first failure validate.All(rules...) // runs every rule, joins the failures with errors.Join; // errors.Is still matches each one validate.Collect(rules...) ``` ## Building blocks | Group | Functions | |---|---| | Compose | `All`, `Collect` | | Presence / equality | `Required`, `Equal`, `In`, `NotIn` | | String length & content | `MinLength`, `MaxLength` (runes), `MinLengthBytes`, `MaxLengthBytes`, `Chars`, `ExceptChars`, `Prefix`, `Suffix`, `Contains`, `Match` | | Formats | `Email`, `URL`, `UUID` | | Numbers | `Min`, `Max`, `MinFloat32`, `MaxFloat32`, `MinFloat64`, `MaxFloat64` | | Slices | `MinSize`, `MaxSize` | | Errors | `Error`, `NewError`, `Err` | Each returns (or is) a `func(T) error`, so anything you write with the same shape composes with them. ## Not a fit if… You want **struct-tag validation**, **translated / i18n messages**, or a **large catalogue** of built-in checks (credit cards, ISO codes, CIDRs, …). Use [`go-playground/validator`](https://github.com/go-playground/validator) for that. This package deliberately stays small. ## License MIT. See [LICENSE.md](./LICENSE.md).