Optional Float64 Validation
Learn how optional float64 validation works in NLG Form using nullable float fields, OptionalFloat64, minimum, maximum, and range validation.
OptionalFloat64 allows decimal validation rules to run only when a nullable float value is present.
This is useful for optional prices, discounts, measurements, scores, coordinates, configuration values, and partial update APIs.
TL;DR
| Helper | Description |
|---|---|
optional.OptionalFloat64(field, rules...) | Runs nested rules only when the float64 pointer is non-nil |
optional.MinFloat64Opt(field, n) | Requires the optional value to be greater than or equal to n |
optional.MinFloat64OptWithCode(field, n, code) | Same as MinFloat64Opt with a custom error code |
optional.MaxFloat64Opt(field, n) | Requires the optional value to be less than or equal to n |
optional.MaxFloat64OptWithCode(field, n, code) | Same as MaxFloat64Opt with a custom error code |
optional.BetweenFloat64Opt(field, min, max) | Requires the optional value to be within a range |
optional.BetweenFloat64OptWithCode(field, min, max, code) | Same as BetweenFloat64Opt with a custom error code |
Defining Optional Float64 Fields
Optional float64 fields use pointer values.
type OptionalFloat64Request struct {
Price *float64 `json:"price"`
Discount *float64 `json:"discount"`
Rating *float64 `json:"rating"`
}Field definitions use form.OptFloat64.
OptionalFloat64Form := struct {
Price form.OptFloat64Field[OptionalFloat64Request]
Discount form.OptFloat64Field[OptionalFloat64Request]
Rating form.OptFloat64Field[OptionalFloat64Request]
}{
Price: form.OptFloat64[OptionalFloat64Request]("price", func(r *OptionalFloat64Request) *float64 {
return r.Price
}),
Discount: form.OptFloat64[OptionalFloat64Request]("discount", func(r *OptionalFloat64Request) *float64 {
return r.Discount
}),
Rating: form.OptFloat64[OptionalFloat64Request]("rating", func(r *OptionalFloat64Request) *float64 {
return r.Rating
}),
}Applying Optional Float64 Rules
return form.Schema[OptionalFloat64Request]{
optional.OptionalFloat64(
OptionalFloat64Form.Price,
optional.MinFloat64Opt(OptionalFloat64Form.Price, 0.01),
),
optional.OptionalFloat64(
OptionalFloat64Form.Discount,
optional.MaxFloat64Opt(OptionalFloat64Form.Discount, 100),
),
optional.OptionalFloat64(
OptionalFloat64Form.Rating,
optional.BetweenFloat64Opt(OptionalFloat64Form.Rating, 1, 5),
),
}Validation behavior:
| Input | Result |
|---|---|
null | skipped |
0.00 | validated |
0.01 | valid for MinFloat64Opt(..., 0.01) |
-1.00 | invalid |
Complete Example
schema.go
package main
import (
"github.com/netlifeguru/form"
"github.com/netlifeguru/form/optional"
)
const (
CodePriceMin = form.Code("price_min")
CodeDiscountMax = form.Code("discount_max")
CodeRatingBetween = form.Code("rating_between")
)
type OptionalFloat64Request struct {
Price *float64 `json:"price"`
Discount *float64 `json:"discount"`
Rating *float64 `json:"rating"`
}
func OptionalFloat64Schema() form.Schema[OptionalFloat64Request] {
OptionalFloat64Form := struct {
Price form.OptFloat64Field[OptionalFloat64Request]
Discount form.OptFloat64Field[OptionalFloat64Request]
Rating form.OptFloat64Field[OptionalFloat64Request]
}{
Price: form.OptFloat64[OptionalFloat64Request]("price", func(r *OptionalFloat64Request) *float64 {
return r.Price
}),
Discount: form.OptFloat64[OptionalFloat64Request]("discount", func(r *OptionalFloat64Request) *float64 {
return r.Discount
}),
Rating: form.OptFloat64[OptionalFloat64Request]("rating", func(r *OptionalFloat64Request) *float64 {
return r.Rating
}),
}
return form.Schema[OptionalFloat64Request]{
optional.OptionalFloat64(
OptionalFloat64Form.Price,
optional.MinFloat64OptWithCode(OptionalFloat64Form.Price, 0.01, CodePriceMin),
),
optional.OptionalFloat64(
OptionalFloat64Form.Discount,
optional.MaxFloat64OptWithCode(OptionalFloat64Form.Discount, 100, CodeDiscountMax),
),
optional.OptionalFloat64(
OptionalFloat64Form.Rating,
optional.BetweenFloat64OptWithCode(OptionalFloat64Form.Rating, 1, 5, CodeRatingBetween),
),
}
}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-float64", "POST", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
var in OptionalFloat64Request
if !httpform.BindAndValidate(w, req, &in, OptionalFloat64Schema(), 1<<20) {
fmt.Println("optional float64 validation failed")
return
}
fmt.Println("optional float64 validation passed:", in)
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]any{
"message": "optional float64 validation passed",
"data": in,
})
})
validPayload := map[string]any{
"price": 10.99,
"discount": 25.5,
"rating": 4.5,
}
invalidPayload := map[string]any{
"price": 0.00,
"discount": 101.0,
"rating": 6.0,
}
skippedPayload := map[string]any{
"price": nil,
"discount": nil,
"rating": nil,
}
fmt.Println("\n--- Valid request ---")
form.SendTestPost(":8080/optional-float64", validPayload)
fmt.Println("\n--- Invalid request ---")
form.SendTestPost(":8080/optional-float64", invalidPayload)
fmt.Println("\n--- Skipped validation request ---")
form.SendTestPost(":8080/optional-float64", skippedPayload)
if err := r.ListenAndServe(8080); err != nil {
slog.Error("failed to start server", "error", err)
os.Exit(1)
}
}Notes
- Optional float64 validation runs only when the pointer is non-nil.
nilvalues are skipped and are not considered validation failures.- Use optional float64 fields for PATCH APIs, nullable database values, and optional decimal input.
- Use
MinFloat64Opt,MaxFloat64Opt, andBetweenFloat64Optfor decimal bounds. - Custom error codes are recommended for public API responses.
- Optional float64 validation remains explicit and transport-independent.
Optional Integer Validation
Learn how optional integer validation works in NLG Form using nullable integer fields, OptionalInt, minimum, maximum, positivity, and range validation.
Optional Time Validation
Learn how optional time validation works in NLG Form using nullable time fields, OptionalTime, date ranges, scheduling validation, and reusable time-based validation pipelines.