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 Pointer Validation

Learn how optional pointer validation works in NLG Form using OptionalPtr, nullable fields, PATCH APIs, nested objects, and reusable conditional validation pipelines.

OptionalPtr is the core primitive behind optional validation in form.

It allows validation rules to execute only when a pointer value exists.

This makes it possible to validate nullable input safely while supporting partial updates, PATCH APIs, optional nested objects, and transport-independent validation workflows.

Why OptionalPtr Exists

Many APIs require fields that:

  • may be omitted
  • may explicitly contain null
  • may appear only during partial updates
  • may be conditionally validated

Examples include:

  • profile updates
  • billing configuration
  • nested settings
  • optional embedded objects
  • optional metadata
  • nullable database fields
  • PATCH endpoints
  • feature toggles
  • optional onboarding sections

OptionalPtr solves this by separating:

  • existence validation
  • value validation

TL;DR

HelperDescription
optional.OptionalPtr(field, rules...)Runs nested rules only when the pointer is non-nil
optional.OptionalPtrWith(field, fn, rules...)Runs rules only when a custom condition passes
optional.OptionalPtrValue(field, value, rules...)Runs rules only when the pointer matches a specific value

Pointer-Based Validation

Optional pointer validation is based on nullable pointer fields.

Example:

type UpdateProfileRequest struct {
	Age      *int     `json:"age"`
	Price    *float64 `json:"price"`
	Nickname *string  `json:"nickname"`
}

This allows the application to distinguish between:

{
  "nickname": null
}

and:

{}

This distinction is extremely important in PATCH APIs and partial updates.

Defining Optional Pointer Fields

Optional pointer fields use typed optional field definitions.

OptionalPtrForm := struct {
	Nickname form.OptStringField[OptionalPtrRequest]
	Age      form.OptIntField[OptionalPtrRequest]
	Price    form.OptFloat64Field[OptionalPtrRequest]
}{
	Nickname: form.OptString[OptionalPtrRequest]("nickname", func(r *OptionalPtrRequest) *string {
		return r.Nickname
	}),
	Age: form.OptInt[OptionalPtrRequest]("age", func(r *OptionalPtrRequest) *int {
		return r.Age
	}),
	Price: form.OptFloat64[OptionalPtrRequest]("price", func(r *OptionalPtrRequest) *float64 {
		return r.Price
	}),
}

Applying OptionalPtr

OptionalPtr executes nested validation rules only when the pointer exists.

return form.Schema[OptionalPtrRequest]{
	optional.OptionalPtr(
		OptionalPtrForm.Nickname.Field,
		rules.MinLen(OptionalPtrForm.Nickname, 3),
	),

	optional.OptionalPtr(
		OptionalPtrForm.Age.Field,
		optional.MinOpt(OptionalPtrForm.Age, 18),
	),
}

Validation behavior:

InputResult
nullskipped
omitted fieldskipped
present valuevalidated

OptionalPtrWith

OptionalPtrWith allows custom conditional execution.

Example:

optional.OptionalPtrWith(
	OptionalPtrForm.Price.Field,
	func(v *float64) bool {
		return v != nil && *v > 0
	},
	optional.MinFloat64Opt(OptionalPtrForm.Price, 1),
)

Typical use cases:

  • conditional billing validation
  • feature-based validation
  • advanced business rules
  • staged onboarding

OptionalPtrValue

OptionalPtrValue runs validation only when the pointer matches a specific value.

Example:

optional.OptionalPtrValue(
	OptionalPtrForm.Role.Field,
	"admin",
	rules.Required(AdminForm.AccessLevel),
)

Typical use cases:

  • role-based validation
  • workflow branching
  • feature toggles
  • conditional form sections

Nested Object Validation

OptionalPtr is especially useful for optional nested objects.

Example:

type Billing struct {
	VAT string `json:"vat"`
}

type Request struct {
	Billing *Billing `json:"billing"`
}

Validation:

optional.OptionalPtr(
	RequestForm.Billing.Field,
	BillingSchema(),
)

This allows nested validation only when the object exists.

Complete Example

schema.go

package main

import (
	"github.com/netlifeguru/form"
	"github.com/netlifeguru/form/optional"
	"github.com/netlifeguru/form/rules"
)

const (
	CodeNicknameMinLen = form.Code("nickname_min_len")
	CodeAgeMin         = form.Code("age_min")
	CodePriceMin       = form.Code("price_min")
)

type OptionalPtrRequest struct {
	Nickname *string  `json:"nickname"`
	Age      *int     `json:"age"`
	Price    *float64 `json:"price"`
}

func OptionalPtrSchema() form.Schema[OptionalPtrRequest] {
	OptionalPtrForm := struct {
		Nickname form.OptStringField[OptionalPtrRequest]
		Age      form.OptIntField[OptionalPtrRequest]
		Price    form.OptFloat64Field[OptionalPtrRequest]
	}{
		Nickname: form.OptString[OptionalPtrRequest]("nickname", func(r *OptionalPtrRequest) *string {
			return r.Nickname
		}),
		Age: form.OptInt[OptionalPtrRequest]("age", func(r *OptionalPtrRequest) *int {
			return r.Age
		}),
		Price: form.OptFloat64[OptionalPtrRequest]("price", func(r *OptionalPtrRequest) *float64 {
			return r.Price
		}),
	}

	return form.Schema[OptionalPtrRequest]{
		optional.OptionalPtr(
			OptionalPtrForm.Nickname.Field,
			rules.MinLenWithCode(OptionalPtrForm.Nickname, 3, CodeNicknameMinLen),
		),

		optional.OptionalPtr(
			OptionalPtrForm.Age.Field,
			optional.MinOptWithCode(OptionalPtrForm.Age, 18, CodeAgeMin),
		),

		optional.OptionalPtr(
			OptionalPtrForm.Price.Field,
			optional.MinFloat64OptWithCode(OptionalPtrForm.Price, 0.01, CodePriceMin),
		),
	}
}

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-ptr", "POST", func(w http.ResponseWriter, req *http.Request, ctx *router.Context) {
		var in OptionalPtrRequest

		if !httpform.BindAndValidate(w, req, &in, OptionalPtrSchema(), 1<<20) {
			fmt.Println("optional ptr validation failed")
			return
		}

		fmt.Println("optional ptr validation passed:", in)

		w.Header().Set("Content-Type", "application/json")

		_ = json.NewEncoder(w).Encode(map[string]any{
			"message": "optional ptr validation passed",
			"data":    in,
		})
	})

	validPayload := map[string]any{
		"nickname": "john",
		"age":      25,
		"price":    19.99,
	}

	invalidPayload := map[string]any{
		"nickname": "ab",
		"age":      10,
		"price":    -1,
	}

	skippedPayload := map[string]any{
		"nickname": nil,
		"age":      nil,
		"price":    nil,
	}

	fmt.Println("\n--- Valid request ---")
	form.SendTestPost(":8080/optional-ptr", validPayload)

	fmt.Println("\n--- Invalid request ---")
	form.SendTestPost(":8080/optional-ptr", invalidPayload)

	fmt.Println("\n--- Skipped validation request ---")
	form.SendTestPost(":8080/optional-ptr", skippedPayload)

	if err := r.ListenAndServe(8080); err != nil {
		slog.Error("failed to start server", "error", err)
		os.Exit(1)
	}
}

Validation Flow

Optional pointer validation behaves like this:

nil pointer
    ↓
validation skipped
non-nil pointer
    ↓
nested rules executed

Notes

  • OptionalPtr is the foundation of nullable validation in form.
  • Validation runs only when the pointer exists.
  • Nil values are intentionally skipped and are not validation failures.
  • Pointer validation is especially useful for PATCH APIs and partial updates.
  • Optional pointer validation supports nested schemas and embedded objects.
  • Optional validation remains explicit and transport-independent.
  • Optional pointer validation helps separate field existence from value correctness.

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.

Optional Slice Validation

Learn how optional slice validation works in NLG Form using OptionalSlice, optional arrays, collection validation, item limits, and reusable validation pipelines.

On this page

Why OptionalPtr ExistsTL;DRPointer-Based ValidationDefining Optional Pointer FieldsApplying OptionalPtrOptionalPtrWithOptionalPtrValueNested Object ValidationComplete Exampleschema.gomain.goValidation FlowNotes