Initialization & Configuration Reference
Complete reference for all Pedantigo initialization methods and configuration options.
Quick Comparison
| API | Use Case | Customizable | Link |
|---|---|---|---|
| Simple API | 80% of cases | No (uses defaults) | → |
| Validator API | Custom options | Yes | → |
| Stream Parser | LLM/partial JSON | Yes | → |
| Union Validator | Discriminated unions | Yes | → |
Simple API
Global functions with automatic caching. Uses DefaultValidatorOptions().
| Function | Description |
|---|---|
pedantigo.Unmarshal[T](data) | Unmarshal JSON and validate |
pedantigo.Validate[T](obj) | Validate existing struct |
pedantigo.NewModel[T](input) | Create from map/struct |
pedantigo.Schema[T]() | Get JSON Schema |
pedantigo.SchemaJSON[T]() | Get JSON Schema as bytes |
pedantigo.SchemaLLM[T]() | Get JSON Schema for LLM APIs (no $schema or $id) |
pedantigo.SchemaJSONLLM[T]() | LLM schema as bytes (no $schema or $id) |
pedantigo.SchemaOpenAPI[T]() | Get OpenAPI 3.1 component schema |
pedantigo.SchemaJSONOpenAPI[T]() | OpenAPI 3.1 schema as bytes |
pedantigo.Marshal[T](obj) | Marshal struct to JSON |
pedantigo.MarshalWithOptions[T](obj, opts) | Marshal with options |
pedantigo.Dict[T](obj) | Convert to map[string]any |
// Simple API: automatic defaults, global caching
user, err := pedantigo.Unmarshal[User](jsonData)
// Equivalent to:
validator := pedantigo.New[User](pedantigo.DefaultValidatorOptions())
user, err := validator.Unmarshal(jsonData)
See Simple API Reference for detailed examples.
Validator API
Explicit validator instances with custom options.
Creating a Validator
| Function | Description |
|---|---|
pedantigo.New[T]() | Create with defaults |
pedantigo.New[T](opts) | Create with custom options |
Validator Methods
| Method | Description |
|---|---|
v.Unmarshal(data) | Unmarshal with validation |
v.Validate(obj) | Validate struct |
v.NewModel(input) | Create from map/struct |
v.Schema() | Get JSON Schema |
v.SchemaJSON() | Schema as bytes |
v.SchemaLLM() | LLM schema (no $schema or $id) |
v.SchemaJSONLLM() | LLM schema as bytes (no $schema or $id) |
v.SchemaOpenAPI() | OpenAPI 3.1 schema |
v.SchemaJSONOpenAPI() | OpenAPI 3.1 as bytes |
v.Marshal(obj) | Marshal to JSON |
v.MarshalWithOptions(obj, opts) | Marshal with options |
v.Dict(obj) | Convert to map |
// Create validator with custom options
validator := pedantigo.New[User](pedantigo.ValidatorOptions{
StrictMissingFields: true,
ExtraFields: pedantigo.ExtraForbid,
})
// Reuse the same validator multiple times
user1, err := validator.Unmarshal(data1)
user2, err := validator.Unmarshal(data2)
// Schema is cached, so subsequent calls are very fast
schema := validator.Schema()
Use the Validator API when you need:
- Custom options
- Schema caching for high-performance scenarios
- Consistent behavior across multiple unmarshal calls
- Explicit control over validator creation
See Validator Reference for detailed examples.
Stream Parser API
For partial/streaming JSON (ideal for LLM outputs).
| Function | Description |
|---|---|
pedantigo.NewStreamParser[T]() | Create with defaults |
pedantigo.NewStreamParser[T](opts) | Create with custom options |
pedantigo.NewStreamParserWithValidator[T](v) | Use existing validator |
Stream Parser Methods
| Method | Description |
|---|---|
sp.Feed(chunk) | Process JSON chunk, returns partial result |
See Streaming Validation for detailed examples.
Union Validator API
For discriminated unions with type switching.
| Function | Description |
|---|---|
pedantigo.NewUnion[T](opts) | Create union validator |
Union Validator Methods
| Method | Description |
|---|---|
uv.Unmarshal(data) | Unmarshal and return variant |
See Unions for detailed examples.
ValidatorOptions
Configuration struct for Validator API, Stream Parser, and Union Validator.
type ValidatorOptions struct {
// StrictMissingFields controls behavior for missing fields
// Default: true (missing fields without defaults cause errors)
StrictMissingFields bool
// ExtraFields controls how unknown JSON fields are handled
// Default: ExtraIgnore (unknown fields are silently ignored)
ExtraFields ExtraFieldsMode
// TagName overrides the global struct tag name for this validator instance
// Default: "" (uses global default "pedantigo")
TagName string
}
| Field | Type | Default | Description |
|---|---|---|---|
StrictMissingFields | bool | true | Missing field handling |
ExtraFields | ExtraFieldsMode | ExtraIgnore | Unknown field handling |
TagName | string | "" | Custom tag name |
Default Options
The default options are optimized for safety and strictness:
pedantigo.DefaultValidatorOptions()
// Returns: ValidatorOptions{
// StrictMissingFields: true,
// ExtraFields: ExtraIgnore,
// TagName: "", // Uses global default "pedantigo"
// }
StrictMissingFields Option
Controls whether missing fields (fields not present in JSON) cause validation errors.
StrictMissingFields: true (Default)
Missing fields without defaults are validation errors:
type Config struct {
Host string `json:"host" pedantigo:"required"`
Port int `json:"port"` // No default
}
jsonData := []byte(`{"host":"localhost"}`)
validator := pedantigo.New[Config](pedantigo.ValidatorOptions{
StrictMissingFields: true,
})
config, err := validator.Unmarshal(jsonData)
// Error: port field is missing and has no default
Use this mode when you want to:
- Catch missing fields as validation errors
- Ensure all fields are explicitly provided in JSON
- Enforce strict API contracts
StrictMissingFields: false
Missing fields without defaults are left as zero values:
type Config struct {
Host string `json:"host" pedantigo:"required"`
Port int `json:"port"` // Zero value: 0
}
jsonData := []byte(`{"host":"localhost"}`)
validator := pedantigo.New[Config](pedantigo.ValidatorOptions{
StrictMissingFields: false,
})
config, err := validator.Unmarshal(jsonData)
// Success: Port is set to 0 (zero value)
fmt.Println(config.Port) // Output: 0
Use this mode when you want to:
- Allow partial JSON input (missing fields get zero values)
- Make most fields optional
- Support backwards-compatible API evolution
How required and json:",omitempty" Interact
Understanding how Go's json:",omitempty" marshaling tag interacts with Pedantigo's required constraint:
| Struct Tags | In JSON Schema required | Unmarshal Behavior |
|---|---|---|
pedantigo:"required" | Yes | Error if field missing from JSON |
json:",omitempty" only | No | Zero value if missing (valid) |
Both required + omitempty | Yes | Error if missing (required wins) |
Pointer *T + required | Yes | Error if missing or null |
Pointer *T without required | No | nil if missing (valid) |
Non-pointer without required | No | Zero value if missing |
Key Points:
json:",omitempty"is for marshaling output - Controls whether zero-value fields are omitted when serialising a struct to JSON. It does not affect validation or schema generation.requiredcontrols both - Affects the schemarequiredarray AND validation (field must be present in JSON input).- Pointers enable true optionality - Use
*Twhen you need to distinguish "missing" from "zero".
type Config struct {
// Required: must be in JSON, appears in schema required array
Host string `json:"host" pedantigo:"required"`
// Optional with omitempty: omitted from output if zero, NOT in required array
Port int `json:"port,omitempty"`
// Optional pointer: nil if missing, distinguishes missing from zero
Timeout *int `json:"timeout,omitempty"`
// Required + omitempty: must be in JSON input, omitted from output if zero
Name string `json:"name,omitempty" pedantigo:"required"`
}
See Schema Generation to understand how these tags affect the generated JSON Schema.
omitempty as a Pedantigo Validation Constraint
In addition to Go's json:",omitempty" marshaling tag, Pedantigo supports omitempty as a validation constraint in
the pedantigo struct tag itself.
type SearchRequest struct {
ActorID string `pedantigo:"omitempty,max=64,required_with=ActorType"`
ActorType string `pedantigo:"omitempty,oneof=user agent system,required_with=ActorID"`
}
Semantics:
When a field is tagged with pedantigo:"omitempty,..." and its value is the zero value for its type (empty string,
0, false, nil pointer, etc.):
- Regular constraints (
min,max,oneof,email,url, etc.) are skipped — the field is treated as intentionally absent. - Cross-field constraints (
required_with,required_if,eqfield,nefield, etc.) always run, regardless of zero-value status, to preserve relational validation semantics.
When the field has a non-zero value, all constraints run normally.
Example — symmetric optional pair:
type Actor struct {
// Both are optional. If one is provided, the other must be too.
ActorID string `pedantigo:"omitempty,max=64,required_with=ActorType"`
ActorType string `pedantigo:"omitempty,oneof=user agent system,required_with=ActorID"`
}
| ActorID | ActorType | Result |
|---|---|---|
"" | "" | Valid — both zero, regular constraints skipped |
"user123" | "user" | Valid — both non-zero, all constraints run |
"user123" | "" | Error on ActorType — required_with=ActorID fires because ActorID is non-zero |
"" | "user" | Error on ActorID — required_with=ActorType fires because ActorType is non-zero |
"user123" | "invalid" | Error on ActorType — oneof fires because field is non-zero |
Difference from json:",omitempty":
| Tag | Where it appears | Effect |
|---|---|---|
json:",omitempty" | JSON struct tag | Controls marshaling output: omits the field from JSON if its value is zero |
pedantigo:"omitempty" | Pedantigo constraint | Controls validation: skips regular constraints when the field value is zero |
Both can be combined:
// Omitted from JSON output when zero AND skips validation when zero
Region string `json:"region,omitempty" pedantigo:"omitempty,oneof=us-east-1 us-west-2 eu-west-1"`
ExtraFields Option
Controls how unknown (extra) JSON fields are handled during unmarshaling.
ExtraIgnore (Default)
Unknown JSON fields are silently ignored:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
jsonData := []byte(`{
"name": "Alice",
"email": "alice@example.com",
"age": 30,
"phone": "555-1234"
}`)
validator := pedantigo.New[User](pedantigo.ValidatorOptions{
ExtraFields: pedantigo.ExtraIgnore,
})
user, err := validator.Unmarshal(jsonData)
// Success: age and phone fields are ignored
Use this mode when you want to:
- Accept JSON with additional fields (future-proofing)
- Ignore client-provided metadata
- Support flexible API clients
ExtraForbid
Unknown JSON fields cause validation errors:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
}
jsonData := []byte(`{
"name": "Alice",
"email": "alice@example.com",
"age": 30
}`)
validator := pedantigo.New[User](pedantigo.ValidatorOptions{
ExtraFields: pedantigo.ExtraForbid,
})
user, err := validator.Unmarshal(jsonData)
// Error: unknown field "age" in JSON
var validationErr *pedantigo.ValidationError
if errors.As(err, &validationErr) {
fmt.Println(validationErr.Errors[0].Message)
// Output: unknown field in JSON
}
Use this mode when you want to:
- Prevent typos in client input
- Detect API misuse
- Enforce strict schema compliance
ExtraAllow
Unknown JSON fields are captured and stored in a designated map[string]any field:
type User struct {
Name string `json:"name"`
Email string `json:"email"`
Extras map[string]any `json:"-" pedantigo:"extra_fields"`
}
jsonData := []byte(`{
"name": "Alice",
"email": "alice@example.com",
"age": 30,
"phone": "555-1234"
}`)
validator := pedantigo.New[User](pedantigo.ValidatorOptions{
ExtraFields: pedantigo.ExtraAllow,
})
user, err := validator.Unmarshal(jsonData)
// Success: unknown fields are captured
fmt.Println(user.Extras["age"]) // Output: 30
fmt.Println(user.Extras["phone"]) // Output: 555-1234
Requirements:
-
Struct must have an extra_fields tagged field:
Extras map[string]any `json:"-" pedantigo:"extra_fields"` -
The field type must be
map[string]any(ormap[string]interface{}) -
Fail-fast validation: If
ExtraAllowis set but noextra_fieldsfield exists,New[T]()panics at startup
Nested Struct Handling:
Each struct level independently handles its own extras. If a nested struct has an extra_fields field, it captures
extras at that level:
type Address struct {
City string `json:"city"`
Extras map[string]any `json:"-" pedantigo:"extra_fields"`
}
type User struct {
Name string `json:"name"`
Address Address `json:"address"`
Extras map[string]any `json:"-" pedantigo:"extra_fields"`
}
jsonData := []byte(`{
"name": "Alice",
"extra_top": "top-level extra",
"address": {
"city": "NYC",
"extra_nested": "nested extra"
}
}`)
// Top-level extras go to User.Extras
// Nested address extras go to Address.Extras
If a nested struct doesn't have an extra_fields field, extras at that level are silently ignored (but the top-level
still requires the field when ExtraAllow is set).
Round-Trip Support:
Extra fields are preserved during marshaling:
user, _ := validator.Unmarshal(jsonData)
// user.Extras contains captured extras
roundTripJSON, _ := validator.Marshal(user)
// roundTripJSON includes both struct fields AND extras
ExtraAllow: Real-World Use Cases
Use Case 1: Multi-Version API Support
When evolving APIs, newer clients may send fields that older server versions don't recognize. ExtraAllow preserves these fields for:
- Forward compatibility: Accept fields from newer clients
- Proxy/gateway scenarios: Pass through unknown fields to downstream services
- Gradual migration: Log unknown fields to understand client adoption
type UserV1 struct {
Name string `json:"name" pedantigo:"required"`
Email string `json:"email" pedantigo:"required,email"`
Extras map[string]any `json:"-" pedantigo:"extra_fields"`
}
// Accept requests from V2 clients that include "profile_picture", "preferences", etc.
// These are captured in Extras for logging/forwarding without breaking V1 logic.
validator := pedantigo.New[UserV1](pedantigo.ValidatorOptions{
ExtraFields: pedantigo.ExtraAllow,
})
user, _ := validator.Unmarshal(requestBody)
if len(user.Extras) > 0 {
log.Printf("Client sent unknown fields: %v", maps.Keys(user.Extras))
// Forward to downstream service that may understand these fields
}
Further Reading:
Use Case 2: LLM Output Capture for Prompt Evaluation
When using LLMs with structured output (JSON mode), models may include unexpected fields. ExtraAllow enables:
- Prompt debugging: Identify when models add unrequested fields
- Model accuracy evaluation: Track field adherence across prompts
- Prompt iteration: Use captured extras to refine instructions
type LLMResponse struct {
Answer string `json:"answer" pedantigo:"required"`
Confidence float64 `json:"confidence"`
Extras map[string]any `json:"-" pedantigo:"extra_fields"`
}
validator := pedantigo.New[LLMResponse](pedantigo.ValidatorOptions{
ExtraFields: pedantigo.ExtraAllow,
})
// Parse LLM output
response, err := validator.Unmarshal(llmOutput)
if err != nil {
// Handle validation error (missing required fields, etc.)
}
// Track extra fields for prompt improvement
if len(response.Extras) > 0 {
log.Printf("LLM included unexpected fields: %v", response.Extras)
// Metrics for evaluating model accuracy
metrics.RecordExtraFields(modelName, promptID, response.Extras)
// Example: {"reasoning": "...", "sources": [...]} - fields LLM added on its own
}
Further Reading:
TagName Option
Override the struct tag name for a specific validator instance.
Default: Uses global tag name ("pedantigo" or set via SetTagName())
| Value | Behavior |
|---|---|
"" (empty) | Use global default |
"validate" | Use go-playground/validator style |
"binding" | Use gin-gonic style |
// Use go-playground/validator style tags
validator := pedantigo.New[User](pedantigo.ValidatorOptions{
TagName: "validate",
})
type User struct {
Name string `json:"name" validate:"required,min=3"`
}
Use Cases:
- Migration from other validation libraries
- Team conventions requiring specific tag names
- Coexistence with other libraries using
pedantigotag
Further Reading:
Choosing the Right Options
| Scenario | StrictMissingFields | ExtraFields | Reason |
|---|---|---|---|
| REST API with strict contracts | true | ExtraForbid | Prevent bugs from typos/API misuse |
| Configuration file parsing | false | ExtraIgnore | Allow partial configs, future-proof |
| During API migration | false | ExtraIgnore | Accept old and new client versions |
| Public web API | true | ExtraIgnore | Strict input, future-proof |
| Internal service API | true | ExtraForbid | Strict both ways |
| Webhook receiver | false | ExtraIgnore | Accept any fields from sender |
| LLM output parsing | true | ExtraAllow | Capture unexpected model outputs |
| API gateway/proxy | false | ExtraAllow | Pass through unknown fields |
Option Combinations
Most Strict
pedantigo.ValidatorOptions{
StrictMissingFields: true,
ExtraFields: pedantigo.ExtraForbid,
}
// Best for: REST API validation, ensuring exact schema match
Most Lenient
pedantigo.ValidatorOptions{
StrictMissingFields: false,
ExtraFields: pedantigo.ExtraIgnore,
}
// Best for: Configuration parsing, webhook receivers, flexible APIs
Balanced (Default)
pedantigo.DefaultValidatorOptions()
// StrictMissingFields: true
// ExtraFields: ExtraIgnore
// Best for: General-purpose APIs, good balance of safety and flexibility
Capture Everything
pedantigo.ValidatorOptions{
StrictMissingFields: false,
ExtraFields: pedantigo.ExtraAllow,
}
// Best for: LLM output parsing, API gateways, forward-compatible services
Complete Examples
API Server with Strict Validation
package main
import (
"errors"
"log"
"github.com/smrutai/pedantigo"
)
type CreateUserRequest struct {
Username string `json:"username" pedantigo:"required,min=3,max=20"`
Email string `json:"email" pedantigo:"required,email"`
Password string `json:"password" pedantigo:"required,min=8"`
}
// API validator: strict about extra fields, requires all fields
var apiValidator = pedantigo.New[CreateUserRequest](
pedantigo.ValidatorOptions{
StrictMissingFields: true,
ExtraFields: pedantigo.ExtraForbid,
},
)
func handleCreateUser(jsonData []byte) (*CreateUserRequest, error) {
req, err := apiValidator.Unmarshal(jsonData)
if err != nil {
var validationErr *pedantigo.ValidationError
if errors.As(err, &validationErr) {
return nil, validationErr
}
return nil, err
}
return req, nil
}
Configuration File Parsing (Lenient)
type AppConfig struct {
Database struct {
Host string `json:"host" pedantigo:"required"`
Port int `json:"port" pedantigo:"default=5432"`
Username string `json:"username" pedantigo:"required"`
Password string `json:"password" pedantigo:"required"`
} `json:"database"`
Server struct {
Addr string `json:"addr" pedantigo:"default=0.0.0.0:8080"`
} `json:"server"`
}
// Config validator: lenient about missing fields, allows extra fields
var configValidator = pedantigo.New[AppConfig](
pedantigo.ValidatorOptions{
StrictMissingFields: false,
ExtraFields: pedantigo.ExtraIgnore,
},
)
Migration-Friendly API
type UserV2 struct {
ID string `json:"id" pedantigo:"required,uuid"`
Username string `json:"username" pedantigo:"required"`
Email string `json:"email" pedantigo:"required,email"`
Status string `json:"status" pedantigo:"default=active"`
}
// Migration validator: accept both old and new client requests
var migrationValidator = pedantigo.New[UserV2](
pedantigo.ValidatorOptions{
StrictMissingFields: false,
ExtraFields: pedantigo.ExtraIgnore,
},
)
Further Reading
Go Documentation:
Specifications:
LLM Structured Outputs: