Optional Integer Validation
Learn how optional integer validation works in NLG Form using nullable integer fields, OptionalInt, minimum, maximum, positivity, and range validation.
OptionalInt allows integer validation rules to run only when a nullable integer value is present.
This is useful for optional counters, quantities, pagination values, priorities, limits, scoring systems, configuration values, and partial update APIs.
TL;DR
| Helper | Description |
|---|---|
optional.OptionalInt(field, rules...) | Runs nested rules only when the integer pointer is non-nil |
optional.MinOpt(field, n) | Requires the optional value to be greater than or equal to n |
optional.MinOptWithCode(field, n, code) | Same as MinOpt with a custom error code |
optional.MaxOpt(field, n) | Requires the optional value to be less than or equal to n |
optional.MaxOptWithCode(field, n, code) | Same as MaxOpt with a custom error code |
optional.BetweenOpt(field, min, max) | Requires the optional value to be within a range |
optional.BetweenOptWithCode(field, min, max, code) | Same as BetweenOpt with a custom error code |
optional.PositiveOpt(field) | Requires the optional value to be positive |
optional.PositiveOptWithCode(field, code) | Same as PositiveOpt with a custom error code |
optional.NegativeOpt(field) | Requires the optional value to be negative |
optional.NegativeOptWithCode(field, code) | Same as NegativeOpt with a custom error code |
Defining Optional Integer Fields
Optional integer fields use pointer values.
type OptionalIntRequest struct {
Age *int `json:"age"`
Quantity *int `json:"quantity"`
Priority *int `json:"priority"`
}Field definitions use form.OptInt.
OptionalIntForm := struct {
Age form.OptIntField[OptionalIntRequest]
Quantity form.OptIntField[OptionalIntRequest]
Priority form.OptIntField[OptionalIntRequest]
}{
Age: form.OptInt[OptionalIntRequest]("age", func(r *OptionalIntRequest) *int {
return r.Age
}),
Quantity: form.OptInt[OptionalIntRequest]("quantity", func(r *OptionalIntRequest) *int {
return r.Quantity
}),
Priority: form.OptInt[OptionalIntRequest]("priority", func(r *OptionalIntRequest) *int {
return r.Priority
}),
}Applying Optional Integer Rules
return form.Schema[OptionalIntRequest]{
optional.OptionalInt(
OptionalIntForm.Age,
optional.MinOpt(OptionalIntForm.Age, 18),
),
optional.OptionalInt(
OptionalIntForm.Quantity,
optional.PositiveOpt(OptionalIntForm.Quantity),
),
optional.OptionalInt(
OptionalIntForm.Priority,
optional.BetweenOpt(OptionalIntForm.Priority, 1, 10),
),
}Validation behavior:
| Input | Result |
|---|---|
null | skipped |
0 | validated |
5 | valid for PositiveOpt |
-1 | invalid for PositiveOpt |
Complete Example
schema.go
package main
import (
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/optional"
)
const (
CodeAgeMin = form.Code("age_min")
CodeQuantityPositive = form.Code("quantity_positive")
CodePriorityRange = form.Code("priority_range")
)
type OptionalIntRequest struct {
Age *int `json:"age"`
Quantity *int `json:"quantity"`
Priority *int `json:"priority"`
}
func OptionalIntSchema() form.Schema[OptionalIntRequest] {
OptionalIntForm := struct {
Age form.OptIntField[OptionalIntRequest]
Quantity form.OptIntField[OptionalIntRequest]
Priority form.OptIntField[OptionalIntRequest]
}{
Age: form.OptInt[OptionalIntRequest]("age", func(r *OptionalIntRequest) *int {
return r.Age
}),
Quantity: form.OptInt[OptionalIntRequest]("quantity", func(r *OptionalIntRequest) *int {
return r.Quantity
}),
Priority: form.OptInt[OptionalIntRequest]("priority", func(r *OptionalIntRequest) *int {
return r.Priority
}),
}
return form.Schema[OptionalIntRequest]{
optional.OptionalInt(
OptionalIntForm.Age,
optional.MinOptWithCode(OptionalIntForm.Age, 18, CodeAgeMin),
),
optional.OptionalInt(
OptionalIntForm.Quantity,
optional.PositiveOptWithCode(OptionalIntForm.Quantity, CodeQuantityPositive),
),
optional.OptionalInt(
OptionalIntForm.Priority,
optional.BetweenOptWithCode(OptionalIntForm.Priority, 1, 10, CodePriorityRange),
),
}
}main.go
package main
import (
"encoding/json"
"fmt"
"log/slog"
"net/http"
"os"
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/httpform"
"github.com/netlifeguru/router"
)
func main() {
r := router.New()
r.HandleFunc("/optional-int", "POST", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
var in OptionalIntRequest
if !httpform.BindAndValidate(w, req, &in, OptionalIntSchema(), 1<<20) {
fmt.Println("optional integer validation failed")
return
}
fmt.Println("optional integer validation passed:", in)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"message": "optional integer validation passed",
"data": in,
})
})
validPayload := map[string]any{
"age": 25,
"quantity": 10,
"priority": 5,
}
invalidPayload := map[string]any{
"age": 10,
"quantity": -1,
"priority": 50,
}
skippedPayload := map[string]any{
"age": nil,
"quantity": nil,
"priority": nil,
}
fmt.Println("\n--- Valid request ---")
form.SendTestPost(":8080/optional-int", validPayload)
fmt.Println("\n--- Invalid request ---")
form.SendTestPost(":8080/optional-int", invalidPayload)
fmt.Println("\n--- Skipped validation request ---")
form.SendTestPost(":8080/optional-int", skippedPayload)
if err := r.ListenAndServe(8080); err != nil {
slog.Error("failed to start server", "error", err)
os.Exit(1)
}
}Notes
- Optional integer validation runs only when the pointer is non-nil.
nilvalues are skipped and are not considered validation failures.- Optional integer fields are useful for PATCH APIs and nullable database values.
- Use
MinOpt,MaxOpt, andBetweenOptfor integer bounds validation. - Use
PositiveOptandNegativeOptfor intent-based numeric validation. - Optional integer validation remains explicit and transport-independent.
- Custom error codes are recommended for frontend-facing APIs and public validation contracts.
Optional String Validation
Learn how optional string validation works in NLG Form using OptionalString, conditional rule execution, blank value skipping, and reusable validation pipelines.
Optional Float64 Validation
Learn how optional float64 validation works in NLG Form using nullable float fields, OptionalFloat64, minimum, maximum, and range validation.