NetLife Guru

Open source Go packages for fast, maintainable web systems. Built with a documentation-first approach.

Product
OverviewGolang packagesNews
Documentation
DocumentationGo LoggerGo RouterGo DB Form
Company
OverviewContactNewsGitHub
Community / Support
Supportinfo@netlife.guru
© 2026 NetLife Guru. All rights reserved.
GitHubinfo@netlife.guru
NetLife GuruNetLife GuruNetLife Guru
NetLife GuruNetLife GuruNetLife Guru
OverviewDocumentationNewsSupportContact

Golang packages

About
Optional ValidationOptional String ValidationOptional Integer ValidationOptional Float64 ValidationOptional Time ValidationOptional Pointer ValidationOptional Slice Validation
Form ValidatorOptional Validation

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

HelperDescription
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:

InputResult
nullskipped
0.00validated
0.01valid for MinFloat64Opt(..., 0.01)
-1.00invalid

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.
  • nil values 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, and BetweenFloat64Opt for 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.

On this page

TL;DRDefining Optional Float64 FieldsApplying Optional Float64 RulesComplete Exampleschema.gomain.goNotes