Zog

website·Indexed 31 days ago

https://zog.dev

A schema builder for Go designed for runtime value parsing, validation, and data transformation. It includes helper packages such as zhttp for JSON, forms, and query params, zjson for parsing JSON into structs, and zenv for validating environment variables. Zog supports custom schemas, i18n for error messages, and provides a distinction between parsing and validation workflows.

Tokens
25.7K
Snippets
132
Records
163
Agent score
58%

What's inside Zog

  1. Overview of Zog Schema Specification (ZSS)

    ZSS (Zog Schema Specification) is an experimental intermediate, structured representation of Zog schemas. It acts as a bridge between Zog's runtime schema definitions and target formats such as JSON Schema, OpenAPI/Swagger specifications, and TypeScript types. Note that ZSS is currently in flux and subject to breaking changes.
  2. Understand Zog validation issues and errors

    Zog distinguishes between Issues and Errors. An Issue is a structured validation result produced by Zod, whereas an Error is the underlying exception (like a JSON unmarshalling failure) that caused the issue. Zog does not throw errors directly; instead, validation tests return a list of issues. Each ZogIssue may optionally wrap an underlying error to provide internal context while maintaining a consistent validation interface.
  3. Understand Zog's issue-based error handling

    In Zog, validation failures are represented as 'Issues' rather than thrown exceptions. Validation tests return structured issues instead of throwing errors directly. If a low-level error occurs (e.g., a JSON unmarshalling failure), Zog wraps that error inside a ZogIssue to provide a consistent validation interface while preserving the internal cause for debugging.
  4. Use the ZogIssue struct for validation details

    The ZogIssue struct contains detailed metadata about a validation failure. Key fields include Code (the unique identifier for the issue), Path (a slice of strings indicating the location of the error in the data structure), Value (the data that caused the issue), Dtype (the destination type), Params (parameters from the test that failed), Message (a human-readable string safe for end-users), and Err (the wrapped internal error).
    type ZogIssue struct {
    	Code zconst.ZogIssueCode
    	Path []string
    	Value any
    	Dtype string
    	Params map[string]any
    	Message string
    	Err error
    }
  5. Understand Zog panic conditions

    Zog panics when fundamental assumptions are broken—specifically when the schema is configured incorrectly. It will NOT panic due to invalid input data, but it will panic if the destination structure does not match the schema definition or if type casts are impossible.
  6. Understand Zog panic behavior

    Zog follows TigerStyle asserts. It will not panic due to invalid input data; however, it will panic if the library is configured incorrectly. This typically happens when a schema definition is incorrect, putting Zog into an invalid state where the schema can never succeed.
  7. Understand the purpose of the zog internals package

    The internals package in zog contains code that is not intended for general user space. Unlike the standard Go internal package (which prevents export to user space), zog allows users to access internals to enable experimentation with new APIs or to build on top of experimental features before they are promoted to the main package.

    Warning: Using the internals package is not recommended for production stability, as the code within it is subject to breaking changes at any time.

  8. Understand Zog's core design and parsing behavior

    Zog follows several core design principles for data parsing and validation:

    • Field Optionality: All fields are optional by default, mirroring GraphQL behavior.
    • Struct Parsing: When parsing into structs, private fields are ignored, consistent with the Go standard library's json.Unmarshal.
    • Test Execution: Tests should not depend on execution order, as they may run in parallel in future versions.
  9. Use zconst for standardized Zog types and error codes

    The zconst package provides a collection of string constants to ensure consistency when handling Zog types and issue codes. While using zconst is optional since all constants are simple strings, it is recommended for formatting errors via a LangMap (a map of ZogType to a map of ZogIssueCode to a localized string).
    // Example of how LangMap is structured using zconst types
    type LangMap = map[zconst.ZogType]map[zconst.ZogIssueCode]string
  10. Define a Zog schema for validation and transformation

    A Zog schema is an interface used to define validation and transformation logic for a variable of a specific type. Schemas are constructed by chaining methods that add constraints or tests to the data pipeline.
    // A required string that is trimmed and must be at least 3 characters long
    stringSchema := z.String().Trim().Min(3).Required()
    
    // A schema for a user struct containing the stringSchema
    userSchema := z.Struct(z.Shape{"name": stringSchema})
  11. Support multiple languages dynamically during parsing

    Use the i18n package to support multiple languages. First, register the supported language maps using i18n.SetLanguagesErrsMap. You can specify a default language and an optional custom key (via i18n.WithLangKey) to identify the language in the parsing context. During execution, pass the desired language key using z.WithCtxValue to determine which language the errors should be returned in.
    import (
    	"github.com/Oudwins/zog/i18n"
    	"github.com/Oudwins/zog/i18n/en"
    	"github.com/Oudwins/zog/i18n/es"
    	"github.com/Oudwins/zog/i18n/ja"
    )
    
    // Initialize language support
    i18n.SetLanguagesErrsMap(map[string]i18n.LangMap{
    	"es": es.Map,
    	"en": en.Map,
    	"ja": ja.Map,
    },
    	"es",                        // default language
    	i18n.WithLangKey("langKey"), // (optional) custom key for context
    )
    
    // Parse with specific languages using the context key
    schema.Parse(data, &dest, z.WithCtxValue("langKey", "es")) // Spanish errors
    schema.Parse(data, &dest, z.WithCtxValue("langKey", "en")) // English errors
    schema.Parse(data, &dest, z.WithCtxValue("langKey", "ja")) // Japanese errors
    schema.Parse(data, &dest)                                  // Default language (Spanish)
  12. Choose between Schema.Parse and Schema.Validate

    Zog provides two primary methods for processing data. Both use the same schemas and can be used interchangeably, but they differ in how they handle input and type conversion.

    • Schema.Parse(data, &dest, ...options): Used when you have raw data that needs to be unmarshaled/converted into a destination structure. It handles type coercion (e.g., converting a string "2024-01-01" to a time.Time object) and zero-value checking for required fields.
    • Schema.Validate(&data, ...options): Used when data is already in the final target structure and you only need to verify its correctness. It is more efficient but does not perform type coercion. It treats zero values as invalid if the schema is marked as .Required().

    Recommendation: Use Validate for better performance if the data is already typed. Use Parse if you need automatic type coercion or need to distinguish between a missing value and a zero value without using pointers.

    // Parse handles coercion
    data := "2024-01-01"
    var dest time.Time
    z.Time().Parse(data, &dest) // Success: dest is now a time.Time
    
    // Validate does NOT handle coercion
    z.Time().Validate(&data)    // Error: string is not a valid time