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
InstallationGetting StartedValidation Philosophy
Form ValidatorGetting Started

Validation Philosophy

Learn how NLG Form uses explicit, type-safe, reusable validation schemas instead of struct tags and reflection-heavy validation pipelines.

Unlike traditional Go validators that rely heavily on struct tags and runtime reflection, form uses explicit, type-safe validation schemas built with reusable fields and composable rules.

The package is designed around:

  • explicit validation logic
  • reusable schema composition
  • type-safe field access
  • transport-independent validation
  • immutable schema definitions
  • reusable validation pipelines

This approach intentionally trades a slightly more verbose setup for improved readability, composability, testability, and long-term maintainability.

Why Not Struct Tags?

Many Go validators use struct tags:

type User struct {
	Email string `validate:"required,email"`
}

While compact, tag-based validation has limitations:

  • validation logic becomes hidden inside struct metadata
  • conditional validation becomes difficult
  • validation rules are harder to reuse
  • tags depend heavily on reflection
  • complex validation flows become difficult to compose
  • transport and validation logic become tightly coupled

form instead treats validation as explicit application logic.

Validation Flow

Validation schemas are built in three steps:

  1. Define typed validation fields
  2. Define validation rules for each field
  3. Combine rules into a reusable schema

Request Structure

The request structure defines the incoming payload.

type PostRequest struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

This structure remains transport-friendly and independent from validation behavior.

Typed Validation Fields

The first section defines reusable typed validation fields.

var PostForm = struct {
	Name form.StringField[PostRequest]
	Age  form.IntField[PostRequest]
}{
	Name: form.Str[PostRequest]("name", func(r *PostRequest) string {
		return r.Name
	}),
	Age: form.Int[PostRequest]("age", func(r *PostRequest) int {
		return r.Age
	}),
}

Each field contains:

  • field metadata
  • typed accessors
  • reusable references for validation rules
  • field names used in validation responses

The accessor function:

func(r *PostRequest) string {
	return r.Name
}

provides type-safe access to the underlying field without relying on reflection-only field lookups.

This allows validation rules to work with strongly typed values while remaining reusable across schemas.

Validation Rules

Validation rules are grouped into reusable schema blocks.

var NameSchema = form.Schema[PostRequest]{
	rules.Required(PostForm.Name),
	rules.MinLen(PostForm.Name, 5),
}

var AgeSchema = form.Schema[PostRequest]{
	rules.RequiredInt(PostForm.Age),
	rules.Min(PostForm.Age, 8),
}

Each rule operates on a typed field reference.

This keeps validation logic:

  • explicit
  • composable
  • testable
  • reusable
  • independent from transport layers

Rules can later be reused across:

  • HTTP handlers
  • CLI tools
  • background workers
  • internal services
  • shared validation packages

Schema Composition

Individual schema blocks are combined into a reusable validation schema.

return form.Rules(
	NameSchema,
	AgeSchema,
)

This produces the final schema used during validation.

The resulting schema can then be reused anywhere in the application.

Why Schemas Are Usually Functions

Schemas are typically defined through functions:

func PostSchema() form.Schema[PostRequest]

instead of global mutable variables.

This keeps validation definitions:

  • immutable
  • isolated
  • reusable
  • safe for application composition
  • predictable during testing

This pattern also makes schema construction explicit and easier to evolve as applications grow.

Design Goals

The package is designed around a few core principles:

  • explicit over implicit
  • reusable over duplicated
  • composable over monolithic
  • type-safe over reflection-heavy
  • transport-independent validation
  • predictable validation behavior

While the setup may initially appear more verbose than tag-based validators, the resulting validation logic becomes significantly easier to maintain in larger applications and distributed systems.

Getting Started

Learn how to validate JSON HTTP requests using reusable schemas, typed validation fields, and structured validation rules with the NLG Form package.

HTTP Responses

Learn how NLG Form binds and validates HTTP JSON requests and returns structured validation responses using map responses, flat responses, custom messages, invalid JSON handling, and unique error codes.

On this page

Why Not Struct Tags?Validation FlowRequest StructureTyped Validation FieldsValidation RulesSchema CompositionWhy Schemas Are Usually FunctionsDesign Goals