Zog
website·Indexed 31 days ago
https://zog.devA 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.
What's inside Zog
- 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.
Understand Zog validation issues and errors
Zog distinguishes between Issues and Errors. AnIssueis a structured validation result produced by Zod, whereas anErroris 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. EachZogIssuemay optionally wrap an underlyingerrorto provide internal context while maintaining a consistent validation interface.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 aZogIssueto provide a consistent validation interface while preserving the internal cause for debugging.Use the ZogIssue struct for validation details
TheZogIssuestruct contains detailed metadata about a validation failure. Key fields includeCode(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), andErr(the wrapped internal error).type ZogIssue struct { Code zconst.ZogIssueCode Path []string Value any Dtype string Params map[string]any Message string Err error }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.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.Understand the purpose of the zog internals package
The
internalspackage inzogcontains code that is not intended for general user space. Unlike the standard Gointernalpackage (which prevents export to user space),zogallows users to accessinternalsto enable experimentation with new APIs or to build on top of experimental features before they are promoted to the main package.Warning: Using the
internalspackage is not recommended for production stability, as the code within it is subject to breaking changes at any time.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.
Use zconst for standardized Zog types and error codes
Thezconstpackage provides a collection of string constants to ensure consistency when handling Zog types and issue codes. While usingzconstis optional since all constants are simple strings, it is recommended for formatting errors via aLangMap(a map ofZogTypeto a map ofZogIssueCodeto a localized string).// Example of how LangMap is structured using zconst types type LangMap = map[zconst.ZogType]map[zconst.ZogIssueCode]stringDefine 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})Support multiple languages dynamically during parsing
Use thei18npackage to support multiple languages. First, register the supported language maps usingi18n.SetLanguagesErrsMap. You can specify a default language and an optional custom key (viai18n.WithLangKey) to identify the language in the parsing context. During execution, pass the desired language key usingz.WithCtxValueto 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)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 atime.Timeobject) 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
Validatefor better performance if the data is already typed. UseParseif 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