Generic Rules
Learn how to validate generic comparable values in NLG Form using reusable allowed-value rules for strings, integers, booleans, enums, statuses, plans, and custom validation codes.
Generic rules validate typed comparable fields through reusable value constraints.
They are useful when a field must match one of a predefined set of allowed values, such as roles, statuses, plans, priorities, levels, feature states, or enum-like application values.
Common Use Cases
Generic rules are commonly used for:
- user roles
- publishing statuses
- subscription plans
- enum-like values
- priority levels
- configuration states
- feature flags
- workflow states
- allowed numeric values
- fixed API contracts
TL;DR
| Rule | Description |
|---|---|
rules.OneOf(field, allowed...) | Requires the field value to match one of the allowed values |
rules.OneOfWithCode(field, code, allowed...) | Same as OneOf with a custom error code |
Defining Generic Fields
Generic rules work with any comparable field value.
GenericForm := struct {
Role form.StringField[GenericRulesRequest]
Level form.IntField[GenericRulesRequest]
Active form.BoolField[GenericRulesRequest]
}{
Role: form.Str[GenericRulesRequest]("role", func(r *GenericRulesRequest) string {
return r.Role
}),
Level: form.Int[GenericRulesRequest]("level", func(r *GenericRulesRequest) int {
return r.Level
}),
Active: form.Bool[GenericRulesRequest]("active", func(r *GenericRulesRequest) bool {
return r.Active
}),
}Generic rules use the underlying field through .Field:
GenericForm.Role.FieldThis allows the same rule to work with different comparable value types.
Applying Generic Rules
Use OneOf when a value must be part of a fixed allowed set.
return form.Schema[GenericRulesRequest]{
rules.OneOf[GenericRulesRequest, string](
GenericForm.Role.Field,
"admin",
"editor",
"viewer",
),
rules.OneOf[GenericRulesRequest, int](
GenericForm.Level.Field,
1,
2,
3,
),
rules.OneOf[GenericRulesRequest, bool](
GenericForm.Active.Field,
true,
),
}Rule Examples
OneOf
Requires the field value to match one of the allowed values.
rules.OneOf[GenericRulesRequest, string](
GenericForm.Role.Field,
"admin",
"editor",
"viewer",
)Typical use cases:
- allowed roles
- enum-like string values
- predefined workflow states
- controlled API input
OneOf with Integers
OneOf can also validate integer values.
rules.OneOf[GenericRulesRequest, int](
GenericForm.Level.Field,
1,
2,
3,
)Typical use cases:
- priority levels
- fixed numeric states
- allowed configuration values
- numeric enum-like input
OneOf with Booleans
OneOf can validate boolean values as well.
rules.OneOf[GenericRulesRequest, bool](
GenericForm.Active.Field,
true,
)This is useful when a boolean value must explicitly match a required state.
OneOfWithCode
Requires the field value to match one of the allowed values and returns a custom validation code.
const CodeInvalidStatus = form.Code("invalid_status")
rules.OneOfWithCode[GenericRulesRequest, string](
GenericForm.Status.Field,
CodeInvalidStatus,
"draft",
"published",
"archived",
)Custom codes are useful for frontend translations, stable API contracts, and consistent validation responses.
Complete Example
package main
import (
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/rules"
)
const (
CodeInvalidStatus = form.Code("invalid_status")
CodeInvalidPlan = form.Code("invalid_plan")
CodeInvalidPriority = form.Code("invalid_priority")
)
type GenericRulesRequest struct {
Role string `json:"role"`
Status string `json:"status"`
Plan string `json:"plan"`
Level int `json:"level"`
Priority int `json:"priority"`
Active bool `json:"active"`
}
func GenericRulesSchema() form.Schema[GenericRulesRequest] {
GenericForm := struct {
Role form.StringField[GenericRulesRequest]
Status form.StringField[GenericRulesRequest]
Plan form.StringField[GenericRulesRequest]
Level form.IntField[GenericRulesRequest]
Priority form.IntField[GenericRulesRequest]
Active form.BoolField[GenericRulesRequest]
}{
Role: form.Str[GenericRulesRequest]("role", func(r *GenericRulesRequest) string {
return r.Role
}),
Status: form.Str[GenericRulesRequest]("status", func(r *GenericRulesRequest) string {
return r.Status
}),
Plan: form.Str[GenericRulesRequest]("plan", func(r *GenericRulesRequest) string {
return r.Plan
}),
Level: form.Int[GenericRulesRequest]("level", func(r *GenericRulesRequest) int {
return r.Level
}),
Priority: form.Int[GenericRulesRequest]("priority", func(r *GenericRulesRequest) int {
return r.Priority
}),
Active: form.Bool[GenericRulesRequest]("active", func(r *GenericRulesRequest) bool {
return r.Active
}),
}
return form.Schema[GenericRulesRequest]{
rules.OneOf[GenericRulesRequest, string](
GenericForm.Role.Field,
"admin",
"editor",
"viewer",
),
rules.OneOfWithCode[GenericRulesRequest, string](
GenericForm.Status.Field,
CodeInvalidStatus,
"draft",
"published",
"archived",
),
rules.OneOfWithCode[GenericRulesRequest, string](
GenericForm.Plan.Field,
CodeInvalidPlan,
"free",
"pro",
"enterprise",
),
rules.OneOf[GenericRulesRequest, int](
GenericForm.Level.Field,
1,
2,
3,
),
rules.OneOfWithCode[GenericRulesRequest, int](
GenericForm.Priority.Field,
CodeInvalidPriority,
10,
20,
30,
),
rules.OneOf[GenericRulesRequest, bool](
GenericForm.Active.Field,
true,
),
}
}Notes
- Generic rules work with comparable Go values.
OneOfis useful for enum-like validation without introducing custom enum types.- Use
OneOfWithCodefor public APIs that require stable error codes. - Empty values are still validated unless optional or conditional logic is used.
- Generic rules use the underlying field through
.Field. - For specialized validation, prefer type-specific rules such as string, integer, boolean, time, or format rules.
- Generic validation remains explicit, reusable, and independent from HTTP or JSON transport layers.