### Transform Data with Zog Preprocess Source: https://github.com/oudwins/zog/blob/master/docs/docs/getting-started.md Illustrates data transformation using Zog's `Preprocess` function. This example splits a comma-separated string into a slice of strings, applying further validation (Trim, Email, Required) to each element in the resulting slice. ```go var dest []string schema := z.Preprocess(func(data any, ctx z.Ctx) ([]string, error) { s := data.(string) // don't do this, actually check the type return strings.Split(s, ","), nil }, z.Slice(z.String().Trim().Email().Required())) errs := schema.Parse("foo@bar.com,bar@foo.com", &dest) // dest = [foo@bar.com bar@foo.com] ``` -------------------------------- ### Install Zog Go Package Source: https://github.com/oudwins/zog/blob/master/README.md This command installs the Zog library using the Go package manager. It fetches the latest version of the library and makes it available for use in your Go projects. ```bash go get github.com/Oudwins/zog ``` -------------------------------- ### Defining Zog Schemas Source: https://github.com/oudwins/zog/blob/master/docs/docs/core-concepts/1-anatomy-of-schema.md Examples of how to instantiate string and struct schemas using the Zog library. ```go stringSchema := z.String().Trim().Min(3).Required() userSchema := z.Struct(z.Shape{"name": stringSchema}) ``` -------------------------------- ### Example: driver.Valuer Pattern with Boxed Schema (Go) Source: https://github.com/oudwins/zog/blob/master/docs/docs/reference.md Demonstrates how to use Zog's Boxed Schema to implement the driver.Valuer interface pattern. This example shows how to define a schema that wraps a string, allowing it to be unboxed from a StringValuer and boxed back into a StringValuer. ```go type StringValuer interface { Value() (string, error) } schema := z.Boxed( z.String().Min(3), func(b StringValuer, ctx z.Ctx) (string, error) { return b.Value() }, func(s string, ctx z.Ctx) (StringValuer, error) { return myStringValuer{v: s}, nil }, // you can pass nil here if you don't need to box values. ) var valuer StringValuer schema.Parse("hello", &valuer) // valuer.Value() will be "hello" valuer = createValuer("hello2") schema.Validate(&valuer) // valuer.Value() will be "hello2" ``` -------------------------------- ### Example: Nullable Pattern with Boxed Schema (Go) Source: https://github.com/oudwins/zog/blob/master/docs/docs/reference.md Illustrates using Zog's Boxed Schema to create a nullable string type, similar to sql.NullString. This example defines how to unbox a NullString, checking its validity, and how to box a string back into a NullString. ```go type NullString struct { String string Valid bool } schema := z.Boxed( z.String().Min(3), func(ns NullString, ctx z.Ctx) (string, error) { if !ns.Valid { return "", errors.New("null string is not valid") } return ns.String, nil }, func(s string, ctx z.Ctx) (NullString, error) { return NullString{String: s, Valid: true}, nil }, ) ``` -------------------------------- ### Example: Omittable Pattern with Boxed Schema (Go) Source: https://github.com/oudwins/zog/blob/master/docs/docs/reference.md Shows how to implement an omittable pattern using Zog's Boxed Schema. This example defines a schema for an optional string, handling cases where the value might be set or not set, and boxing/unboxing accordingly. ```go type Omittable[T any] interface { Value() T IsSet() bool } schema := z.Boxed( z.Ptr(z.String().Min(3)), func(o Omittable[string], ctx z.Ctx) (*string, error) { if o.IsSet() { val := o.Value() return &val, nil } return nil, nil }, func(s *string, ctx z.Ctx) (Omittable[string], error) { return createOmittable(s), nil }, ) ``` -------------------------------- ### Preprocess Data with Go Functions Source: https://context7.com/oudwins/zog/llms.txt Demonstrates how to preprocess input data using custom Go functions for type coercion and data transformation. It includes examples for splitting comma-separated strings and normalizing map data into a struct. ```go import ( z "github.com/Oudwins/zog" "strings" "fmt" ) // Split comma-separated string into slice splitSchema := z.Preprocess( func(data any, ctx z.Ctx) ([]string, error) { str, ok := data.(string) if !ok { return nil, fmt.Errorf("expected string, got %T", data) } return strings.Split(str, ","), nil }, z.Slice(z.String().Trim().Required()), ) var emails []string errs := splitSchema.Parse("user1@example.com,user2@example.com", &emails) // emails = ["user1@example.com", "user2@example.com"] // Convert map to struct type UserInput struct { FirstName string LastName string } normalizeSchema := z.Preprocess( func(data any, ctx z.Ctx) (map[string]any, error) { m, ok := data.(map[string]any) if !ok { return nil, fmt.Errorf("expected map") } // Normalize field names normalized := map[string]any{ "FirstName": m["first_name"], "LastName": m["last_name"], } return normalized, nil }, z.Struct(z.Shape{ "FirstName": z.String().Required(), "LastName": z.String().Required(), }), ) ``` -------------------------------- ### Validate Signup Form with Zog and Templ Source: https://github.com/oudwins/zog/blob/master/docs/docs/examples-of-use/html-templates.md This example defines a Zog schema for signup data and demonstrates how to parse HTTP requests within a handler. It also shows how to pass validation errors to a templ component to display field-specific error messages. ```go type SignupFormData struct { Email string Password string } schema := z.Struct(z.Shape{ "email": z.String().Email().Required(), "password": z.String().Min(8).Required(), }) func handleSignup(w http.ResponseWriter, r *http.Request) { var signupFormData = SignupFormData{} errs := schema.Parse(zhttp.Request(r), &signupFormData) if errs != nil { www.Render(signupFormTempl(&signupFormData, errs)) } // handle successful signup } templ signupFormTempl(data *SignupFormData, errs z.ZogErrMap) { // display only the first error if e, ok := errs["email"]; ok {

{e[0].Message}

} // display only the first error if e, ok := errs["password"]; ok {

{e[0].Message}

} } ``` -------------------------------- ### ZSS with Exhaustive Metadata Example Source: https://github.com/oudwins/zog/blob/master/docs/docs/experimental/zss.md Illustrates the ZSS output when exhaustive metadata is enabled. This example shows how time formats specified via z.Time.Format and custom validation messages set via z.Message are included in the generated ZSS document. ```go // With exhaustive metadata enabled schema := z.Time(z.Time.Format(time.RFC3339)) schema := z.String().Min(5, z.Message("Custom validation message")) zssDoc := z.EXPERIMENTAL_TO_ZSS(schema) // Format and custom messages will be included in zssDoc ``` -------------------------------- ### Basic Schema Parsing with schema.Parse() in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/core-concepts/3-parsing.mdx Demonstrates the fundamental usage of schema.Parse() to validate and parse data into a destination pointer. It shows examples for parsing into a string and a struct, highlighting Zog's ability to handle different schema types. ```go package main import ( "fmt" "github.com/outlive/zog" ) type User struct { Name string `zog:"name"` } func main() { // Parse into a string var destString string zog.String().Min(3).Parse("test", &destString) fmt.Printf("Parsed string: %s\n", destString) // Parse into a struct var destUser User zog.Struct(zog.Shape{"name": zog.String().Min(3)}).Parse(map[string]any{"name": "test"}, &destUser) fmt.Printf("Parsed user: %+v\n", destUser) } ``` -------------------------------- ### Go Preprocess Function Signature and Usage Source: https://github.com/oudwins/zog/blob/master/docs/docs/preprocess.md Defines the Go signature for the Preprocess function and provides a usage example for splitting a string into a slice of strings. It highlights the generic types F and T and the context Ctx. ```go func Preprocess[F any, T any](fn func(data F, ctx Ctx) (out T, err error), schema ZogSchema) *PreprocessSchema[F, T] // Usage: // Note that even if preprocess takes a generic [F]rom type, my recommendation is to always set that to any unless you are 100% sure that the input data will always be of a specific type. Since if you are using this schema with schema.Parse() the input data can be anything. z.Preprocess(func(data any, ctx z.ctx) (any, error) { s, ok := data.(string) if !ok { return nil, fmt.Errorf("expected string but got %T", data) } return strings.split(s, ","), nil }, z.Slice(z.String())) ``` -------------------------------- ### Implement Custom MinLength String Schema - Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/experimental/custom-schemas.md This Go code provides a complete example of a custom schema that validates a string's minimum length. It demonstrates implementing the Process, Validate, GetType, and SetCoercer methods of the EXPERIMENTAL_PUBLIC_ZOG_SCHEMA interface. ```go import ( "fmt" z "github.com/Oudwins/zog" p "github.com/Oudwins/zog/pkgs/internals" "github.com/Oudwins/zog/zconst" ) type MinLengthSchema struct { minLength int errorMsg string coercer z.CoercerFunc } func (s *MinLengthSchema) Process(ctx *internals.SchemaCtx) { // Optional: handle coercion if s.coercer != nil { coerced, err := s.coercer(ctx.Data) if err != nil { ctx.AddIssue(ctx.IssueFromCoerce(err)) return } ctx.Data = coerced } // Type assertion ptr, ok := ctx.ValPtr.(*string) if !ok { ctx.AddIssue(ctx.IssueFromCoerce( fmt.Errorf("expected *string, got %T", ctx.ValPtr))) return } val, ok := ctx.Data.(string) if !ok { ctx.AddIssue(ctx.IssueFromCoerce( fmt.Errorf("expected string, got %T", ctx.Data))) return } // Assign value *ptr = val // Validate if len(val) < s.minLength { issue := ctx.Issue().SetMessage(s.errorMsg) ctx.AddIssue(issue) } } func (s *MinLengthSchema) Validate(ctx *internals.SchemaCtx) { ptr, ok := ctx.ValPtr.(*string) if !ok { return } if len(*ptr) < s.minLength { issue := ctx.Issue().SetMessage(s.errorMsg) ctx.AddIssue(issue) } } func (s *MinLengthSchema) GetType() zconst.ZogType { return zconst.TypeString } func (s *MinLengthSchema) SetCoercer(c z.CoercerFunc) { s.coercer = c } // Usage schema := z.Struct(z.Shape{ "name": z.Use(&MinLengthSchema{ minLength: 5, errorMsg: "name must be at least 5 characters", }), }) ``` -------------------------------- ### Parse Individual Fields with Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/getting-started.md Shows how to use Zog to parse and validate individual fields, such as a time.Time value. The `Time().Required().Parse()` method validates a string input against the expected time format and ensures the field is present. ```go var t time.Time // All schemas now return ZogIssueList errs := Time().Required().Parse("2020-01-01T00:00:00Z", &t) ``` -------------------------------- ### Parse HTTP Request Data with Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/getting-started.md Integrates Zog with HTTP requests using the `zhttp` package. This snippet shows how to parse data directly from an HTTP request (like JSON, form, or query parameters) into a Zog schema and a Go struct. ```go import ( zhttp "github.com/Oudwins/zog/zhttp" ) err := userSchema.Parse(zhttp.Request(r), &user) ``` -------------------------------- ### Illustrate Path Field Usage in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/errors/overview.md Demonstrates how the `Path` field within a `ZogIssue` indicates the location of an issue in nested data structures. It shows examples for root-level primitives, struct fields, and nested structs/slices, including how to convert the path to a string. ```go // String schema - Path is nil for root-level primitive // errList := z.String().Min(5).Email().Parse("foo", &dest) // errList[0].Path = nil, errList[0].Message = "min length is 5" // Struct schema - Path contains the field name as a slice // errList := z.Struct(z.Shape{"name": z.String().Min(5)}).Parse(data, &dest) // errList[0].Path = []string{"name"}, errList[0].Message = "min length is 5" // Nested structs and slices - Path is a slice of path segments // errList := z.Struct(z.Shape{ // "address": z.Struct(z.Shape{ // "streets": z.Slice(z.String().Min(10)), // }), // }).Parse(data, &dest) // errList[0].Path = []string{"address", "streets", "[0]"}, errList[0].Message = "min length is 10" // You can convert Path to a string using Issues.FlattenPath(issue.Path) or issue.PathString() ``` -------------------------------- ### Go: Zog validation with pointer fields and zero-value handling Source: https://context7.com/oudwins/zog/llms.txt Shows how to define Zog schemas for Go structs that include pointer fields, specifically demonstrating how to handle zero-value cases correctly. This example validates a pointer to an integer, allowing for zero values when the pointer itself is present. Requires the 'zog' library. ```go import z "github.com/Oudwins/zog" import "log" // Validate with pointer for zero-value handling type Order struct { Quantity *int } var orderSchema = z.Struct(z.Shape{ "Quantity": z.Ptr(z.Int().GT(0)).NotNil(), }) // Example usage: // qty := 0 // order := &Order{Quantity: &qty} // errs := orderSchema.Validate(order) // Valid - 0 is allowed when using pointer // if errs != nil { // log.Printf("Order invalid: %s", z.Issues.Prettify(errs)) // } ``` -------------------------------- ### Complex Custom Test with Test - Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/custom-tests.md Shows how to implement complex custom tests using Zog's `Test` method, which offers more flexibility than `TestFunc`. This example simulates a database call to validate a user session, utilizing the Zog context to add issues. ```go sessionSchema := z.String().Test(z.Test{ Func: func (val any, ctx z.Ctx) { session := val.(string) if !sessionStore.IsValid(session) { // This ctx.Issue() is a shortcut to creating Zog issues that are aware of the current schema context. Basically this means that it will prefil some data like the path, value, etc. for you. ctx.AddIssue(ctx.Issue().SetMessage("Invalid session")) return } if sessionStore.HasExpired(session) { // But you can also just use the normal z.Issue{} struct if you want to. ctx.AddIssue(z.Issue{ Message: "Session expired", Path: "session", Value: val, }) return } if sessionStore.IsRevoked(session) { ctx.AddIssue(ctx.Issue().SetMessage("Session revoked")) return } // etc } }) ``` -------------------------------- ### Boxed Schema Creation and Usage Source: https://github.com/oudwins/zog/blob/master/docs/docs/reference.md Demonstrates how to create and use boxed schemas in Zog for custom type wrapping and value extraction, including examples for driver.Valuer, Nullable types, and Omittable patterns. ```APIDOC ## Boxed Schema API ### Description Boxed schemas allow you to wrap any Zog schema with custom box/unbox logic. This is useful for working with types that wrap primitive values (like `sql.NullString`) or implementing custom value extraction patterns (like the `driver.Valuer` interface). ### Function Signature ```go type UnboxFunc[B any, T any] func(data B, ctx Ctx) (T, error) type CreateBoxFunc[T any, B any] func(data T, ctx Ctx) (B, error) z.Boxed[B, T](schema ZogSchema, unboxFunc UnboxFunc[B, T], boxFunc CreateBoxFunc[T, B]) *BoxedSchema[B, T] ``` ### Parameters - **B** (type) - Type parameter for the boxed type (the wrapper type). - **T** (type) - Type parameter for the inner type (the type that the schema validates). - **schema** (ZogSchema) - The Zog schema to validate the inner type. - **unboxFunc** (UnboxFunc[B, T]) - Function to extract the inner value from the box. - **boxFunc** (CreateBoxFunc[T, B]) - Function to create a new box from the validated inner value. ### Usage Examples #### Example 1: driver.Valuer pattern ```go // Define the StringValuer interface interface StringValuer { Value() (string, error) } // Create a boxed schema for StringValuer let schema = z.Boxed( z.String().Min(3), func(b StringValuer, ctx z.Ctx) (string, error) { return b.Value() }, func(s string, ctx z.Ctx) (StringValuer, error) { return myStringValuer{v: s}, nil } // you can pass nil here if you don't need to box values. ) // Parse and Validate examples var valuer StringValuer schema.Parse("hello", &valuer) // valuer.Value() will be "hello" valuer = createValuer("hello2") schema.Validate(&valuer) // valuer.Value() will be "hello2" ``` #### Example 2: Nullable pattern (like sql.NullString) ```go // Define the NullString struct struct NullString { String string Valid bool } // Create a boxed schema for NullString let schema = z.Boxed( z.String().Min(3), func(ns NullString, ctx z.Ctx) (string, error) { if (!ns.Valid) { return "", errors.New("null string is not valid") } return ns.String, nil }, func(s string, ctx z.Ctx) (NullString, error) { return NullString{String: s, Valid: true}, nil } ) ``` #### Example 3: Omittable pattern ```go // Define the Omittable interface interface Omittable[T any] { Value() T IsSet() bool } // Create a boxed schema for Omittable let schema = z.Boxed( z.Ptr(z.String().Min(3)), func(o Omittable[string], ctx z.Ctx) (*string, error) { if (o.IsSet()) { let val = o.Value() return &val, nil } return nil, nil }, func(s *string, ctx z.Ctx) (Omittable[string], error) { return createOmittable(s), nil } ) ``` ### Parse vs Validate - **Parse**: Accepts raw data, box values (`B`), or pointers to boxes (`*B`). If the input is a box, it unboxes it first before processing. The value will be boxed back into the original type if a `boxFunc` is provided. - **Validate**: Validates an existing box value, applies transformations, and re-boxes the result back into the original box if a `boxFunc` is provided. ### Notes - Transforms, defaults, catch values, and all other schema features work normally and propagate back to the box. - Boxed schemas can be nested inside Struct schemas. - The `boxFunc` is called after validation/transformation to create the final boxed value. ``` -------------------------------- ### Transform Validated Data with Go Functions Source: https://context7.com/oudwins/zog/llms.txt Shows how to apply transformations to data after it has been validated within the Zog validation pipeline. Examples include string transformations like converting to lowercase and struct-level transformations to calculate values. ```go import ( z "github.com/Oudwins/zog" "strings" ) // String transformations usernameSchema := z.String(). Required(). Trim(). Transform(func(val *string, ctx z.Ctx) error { *val = strings.ToLower(*val) return nil }). Min(3). Max(20) var username string errs := usernameSchema.Parse(" JohnDoe ", &username) // username = "johndoe" // Struct-level transformation type Order struct { Items []string Quantity int Total float64 } orderSchema := z.Struct(z.Shape{ "Items": z.Slice(z.String()).Min(1), "Quantity": z.Int().GT(0), "Total": z.Float64(), }).Transform(func(val any, ctx z.Ctx) error { order := val.(*Order) // Calculate total based on quantity order.Total = float64(order.Quantity) * 10.0 return nil }) ``` -------------------------------- ### Parsing Structs with Zog Schema Tags in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/core-concepts/3-parsing.mdx Illustrates how Zog utilizes struct tags to map input data keys to struct fields, overriding the default behavior. It explains the priority order of tags (json, form, query, env, zog) and provides an example of mixing these tags. ```go package main import ( "fmt" "github.com/outlive/zog" ) type User struct { Name string `zog:"first-name"` LastName string `query:"last_name" json:"last-name"` } func main() { // Example demonstrating mixed struct tags for parsing zog.Struct(zog.Shape{"name": zog.String(), "lastName": zog.String()}).Parse(map[string]any{"first-name": "test", "last-name": "Doe"}, &User{}) // Note: The actual parsing logic would typically involve a map or similar input structure. // This example focuses on the struct definition and tag usage. fmt.Println("Struct with mixed tags defined.") } ``` -------------------------------- ### Define and Parse Environment Variables with zenv Source: https://github.com/oudwins/zog/blob/master/docs/docs/packages/zenv.md This snippet demonstrates how to define a configuration schema using zog and parse environment variables into a Go struct. It includes examples of setting default values, defining constraints, and handling initialization errors. ```go import ( z "github.com/Oudwins/zog" "github.com/Oudwins/zog/zenv" ) var envSchema = z.Struct(z.Shape{ "PORT": z.Int().GT(1000).LT(65535).Default(3000), "DB": z.Struct(z.Shape{ "Host": z.String().Default("localhost"), "User": z.String().Default("root"), "Pass": z.String().Default("root"), }), }) var Env = struct { PORT int DB struct { Host string `env:"DB_HOST"` User string `zog:"DB_USER"` Pass string `env:"DB_PASS"` } }{} func Init() { errs := envSchema.Parse(zenv.NewDataProvider(), &Env) if errs != nil { log.Fatal(errs) } } func Parse() env { var e env errs := envSchema.Parse(zenv.NewDataProvider(), &e) if errs != nil { fmt.Println("FAILURE TO PARSE ENV VARIABLES") log.Fatal(z.Issues.SanitizeMap(errs)) } return e } ``` -------------------------------- ### Implement Quick Custom Schema Validation with CustomFunc in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/custom-schemas.md Shows how to use Zog's `CustomFunc` in Go to create a simple custom schema for validation without defining a full schema. This is useful for types that are not primitives or when a full schema implementation is not desired. It includes the function signature and an example of its usage for validating a UUID. ```go // fn signature func CustomFunc[T any](fn func(valPtr *T, ctx z.Ctx) bool, opts ...z.TestOption) *z.Custom[T] { // ... implementation details ... } // Usage example: user := z.Struct(z.Shape{ "uuid": z.CustomFunc(func(valPtr *uuid.UUID, ctx z.Ctx) bool { return (*valPtr).IsValid() }, z.Message("invalid uuid")), }) ``` -------------------------------- ### Parse JSON Data with Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/getting-started.md Utilizes the `zjson` package to parse JSON data into a Zog schema and a Go struct. This is helpful when you have JSON data in byte format and need to validate and unmarshal it efficiently. ```go import ( zjson "github.com/Oudwins/zog/zjson" ) err := userSchema.Parse(zjson.Decode(bytes.NewReader(jsonBytes)), &user) ``` -------------------------------- ### Validate Data with Zog Schema Parse in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/getting-started.md Shows how to use the `userSchema.Parse()` method to validate a map against the defined User struct. This method attempts to parse and validate input data, populating the provided struct. It handles optional fields by default and returns a list of validation errors if any occur. ```go func main() { u := User{} m := map[string]string{ "name": "Zog", "age": "", // won't return an error because fields are optional by default } err := userSchema.Parse(m, &u) if err != nil { // handle errors -> see Errors section for _, issue := range err { fmt.Printf("%s: %s\n", issue.Path, issue.Message) } } u.Name // "Zog" // note that this might look weird but we didn't say age was required so Zog just skipped the empty string and we are left with the uninitialized int // If we need 0 to be a valid value for age we can use a pointer to an int which will be nil if the value was not present in the input data u.Age // 0 } ``` -------------------------------- ### Define and Parse String Schemas in Go Source: https://context7.com/oudwins/zog/llms.txt Demonstrates how to create string schemas with validators like email, UUID, regex, and length constraints. It shows how to use Parse() to transform and validate input into Go variables. ```go import z "github.com/Oudwins/zog" nameSchema := z.String(). Required(). Min(2, z.Message("Name must be at least 2 characters")). Max(50). Trim() emailSchema := z.String(). Required(). Email(z.Message("Invalid email format")) passwordSchema := z.String(). Required(). Min(8). ContainsUpper(). ContainsDigit(). ContainsSpecial() var name string errs := nameSchema.Parse(" John Doe ", &name) var email string errs = emailSchema.Parse("user@example.com", &email) uuidSchema := z.String().Required().UUID() var id string errs = uuidSchema.Parse("550e8400-e29b-41d4-a716-446655440000", &id) codeSchema := z.String().Match(regexp.MustCompile(`^[A-Z]{3}-\d{4}$`)) var code string errs = codeSchema.Parse("ABC-1234", &code) statusSchema := z.String().OneOf([]string{"pending", "active", "completed"}) var status string errs = statusSchema.Parse("active", &status) ``` -------------------------------- ### Create Custom Validation Tests in Go Source: https://context7.com/oudwins/zog/llms.txt Explains how to implement custom validation logic in Go using Zog's testing framework. It covers simple validations with `TestFunc` and complex scenarios with multiple issues using `Test`. ```go import z "github.com/Oudwins/zog" import "strings" import "fmt" // Simple custom test with TestFunc evenNumberSchema := z.Int().TestFunc(func(val *int, ctx z.Ctx) bool { return *val%2 == 0 }, z.Message("Number must be even")) var num int errs := evenNumberSchema.Parse(4, &num) // valid errs = evenNumberSchema.Parse(5, &num) // invalid // Complex custom test with multiple issues type Registration struct { Password string ConfirmPassword string } registrationSchema := z.Struct(z.Shape{ "Password": z.String().Required().Min(8), "ConfirmPassword": z.String().Required(), }).Test(z.Test{ Func: func(val any, ctx z.Ctx) { reg := val.(*Registration) if reg.Password != reg.ConfirmPassword { ctx.AddIssue(ctx.Issue(). SetMessage("Passwords do not match"). SetPath([]string{"ConfirmPassword"})) } }, }) // Reusable test function func MinWords(min int) z.Test { return z.Test{ Func: func(val any, ctx z.Ctx) { str := val.(*string) words := strings.Fields(*str) if len(words) < min { ctx.AddIssue(ctx.Issue(). SetMessage(fmt.Sprintf("Must contain at least %d words", min))) } }, } } bioSchema := z.String().Test(MinWords(10)) ``` -------------------------------- ### Handle optional and required pointers in Zog Source: https://context7.com/oudwins/zog/llms.txt Explains how to use pointer schemas to handle optional fields that may be nil, or enforce non-nil requirements for pointer types. ```go import z "github.com/Oudwins/zog" optionalNameSchema := z.Ptr(z.String().Min(2)) requiredPtrSchema := z.Ptr(z.Int().GT(0)).NotNil() type Config struct { Debug bool Port int } configSchema := z.Ptr(z.Struct(z.Shape{ "Debug": z.Bool().Default(false), "Port": z.Int().Default(8080), })) ``` -------------------------------- ### Configure Multiple Languages for Dynamic Parsing Source: https://github.com/oudwins/zog/blob/master/docs/docs/packages/i18n.md Shows how to register multiple language maps and set a default language. It also demonstrates how to switch languages during parsing using context values. ```go import ( "github.com/Oudwins/zog/i18n" "github.com/Oudwins/zog/i18n/en" "github.com/Oudwins/zog/i18n/es" "github.com/Oudwins/zog/i18n/ja" ) i18n.SetLanguagesErrsMap(map[string]i18n.LangMap{ "es": es.Map, "en": en.Map, "ja": ja.Map, }, "es", i18n.WithLangKey("langKey"), ) // Usage during parsing schema.Parse(data, &dest, z.WithCtxValue("langKey", "es")) schema.Parse(data, &dest, z.WithCtxValue("langKey", "en")) schema.Parse(data, &dest, z.WithCtxValue("langKey", "ja")) schema.Parse(data, &dest) ``` -------------------------------- ### Use Custom Schema Wrapper - Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/experimental/custom-schemas.md This Go snippet shows how to wrap a custom schema implementation with `z.Use()`. This allows the custom schema to be integrated seamlessly anywhere a Zog schema is expected, such as within structs, slices, or pointers. ```go customSchema := &MyCustomSchema{...} schema := z.Use(customSchema) ``` -------------------------------- ### Validate Environment Variables with Zog Source: https://github.com/oudwins/zog/blob/master/README.md Shows how to use the zenv package to map and validate system environment variables against a predefined Zog schema. ```go import ( zenv "github.com/Oudwins/zog/zenv" ) err := envSchema.Parse(zenv.NewDataProvider(), &envs) ``` -------------------------------- ### Benchmark Results: Reusing Schema vs. Creating New Schema in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/advanced/performance.md Compares the performance of reusing a Zog schema versus creating a new one for each request. The results show significant improvements in speed and reduced allocations when reusing schemas, especially for complex structures. ```bash # Reusing the schema BenchmarkStructComplexSuccess/Success-12 330733 3626 ns/op 451 B/op 28 allocs/op BenchmarkStructComplexSuccessParallel/Success-12 1000000 1294 ns/op 476 B/op 28 allocs/op BenchmarkStructComplexFailure/Error-12 124696 8428 ns/op 1395 B/op 59 allocs/op BenchmarkStructComplexFailureParallel/Error-12 465020 3047 ns/op 1410 B/op 57 allocs/op # Creating a new schema for each execution BenchmarkStructComplexCreateSuccess/Success-12 119824 8757 ns/op 9702 B/op 114 allocs/op BenchmarkStructComplexCreateSuccessParallel/Success-12 294409 4607 ns/op 9905 B/op 114 allocs/op BenchmarkStructComplexCreateFailure/Error-12 80371 14069 ns/op 10652 B/op 145 allocs/op BenchmarkStructComplexCreateFailureParallel/Error-12 192896 6993 ns/op 10793 B/op 144 allocs/op ``` -------------------------------- ### Configuring Test Options Source: https://github.com/oudwins/zog/blob/master/docs/docs/core-concepts/1-anatomy-of-schema.md Demonstrates how to customize validation error messages, issue codes, and paths for Zog tests. ```go z.String().Min(3, z.Message("String must be at least 3 characters long")) z.String().Min(3, z.IssueCode("min_3")) z.String().Min(3, z.IssuePath("name")) ``` -------------------------------- ### Implement Type Coercion for Custom Schema - Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/experimental/custom-schemas.md This Go example illustrates how to set a type coercion function for a custom Zog schema. The `CoercerFunc` is called during the `Process` method to convert input data from one type to another before validation and assignment. ```go type CoercerFunc func(original any) (value any, err error) customSchema.SetCoercer(func(original any) (value any, err error) { if i, ok := original.(int); ok { return strconv.Itoa(i), nil } return nil, fmt.Errorf("cannot convert %T to string", original) }) ``` -------------------------------- ### Validate Environment Variables with zenv Source: https://context7.com/oudwins/zog/llms.txt Explains how to use zenv to load and validate environment variables into a configuration struct. It supports default values and type coercion. ```go import ( z "github.com/Oudwins/zog" "github.com/Oudwins/zog/zenv" "log" ) type Config struct { Port int DatabaseURL string Debug bool MaxWorkers int } var configSchema = z.Struct(z.Shape{ "Port": z.Int().Default(8080).GT(0).LT(65536), "DatabaseURL": z.String().Required(z.Message("DATABASE_URL is required")), "Debug": z.Bool().Default(false), "MaxWorkers": z.Int().Default(4).GT(0).LTE(100), }) var Env Config func InitConfig() { errs := configSchema.Parse(zenv.NewDataProvider(), &Env) if errs != nil { log.Fatalf("Configuration error:\n%s", z.Issues.Prettify(errs)) } } ``` -------------------------------- ### Go: Type Cast Errors - Invalid Type for Schema in Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/philosophy/panics.md Explains type cast errors in Zog when the destination value's type does not match the schema's expected type. This includes examples with custom types and missing z.Ptr, leading to panics during validation. ```go type MyString string type User struct { Age MyString } var schema = z.Struct(z.Schema{ "age": z.String().Required(), }) val := User{ Age: MyString("1"), } schema.Validate(&val) // This will panic because the schema is expecting a string but the value is of type MyString type User struct { ID uuid.UUID } var schema = z.Struct(z.Schema{ "id": z.Custom(func (ptr *string, ctx z.Ctx) bool { // Zog can't convert a UUID to a string so this will panic return true }), }) val := User{ ID: uuid.New(), } schema.Validate(&val) // This will panic because the schema is expecting a string but the value is of type uuid.UUID type User struct { Friends *[]Friend } // This is incorrect! var schema = z.Struct(z.Schema{ "friends": z.Slice(z.Struct(z.Schema{ "name": z.String().Required(), })), }) // This is correct! var schema2 = z.Struct(z.Schema{ "friends": z.Ptr(z.Slice(z.Struct(z.Schema{ "name": z.String().Required(), }))), }) ``` -------------------------------- ### Parse and Validate HTTP Requests with zhttp Source: https://context7.com/oudwins/zog/llms.txt Demonstrates how to use zhttp to automatically parse and validate incoming HTTP requests. It supports JSON, form data, and query parameters based on the Content-Type header. ```go import ( z "github.com/Oudwins/zog" "github.com/Oudwins/zog/zhttp" "net/http" ) type CreateUserRequest struct { Name string Email string Age int } var createUserSchema = z.Struct(z.Shape{ "Name": z.String().Required().Min(2).Max(100), "Email": z.String().Required().Email(), "Age": z.Int().GT(0).LT(150), }) func CreateUserHandler(w http.ResponseWriter, r *http.Request) { var req CreateUserRequest errs := createUserSchema.Parse(zhttp.Request(r), &req) if errs != nil { w.WriteHeader(http.StatusBadRequest) json.NewEncoder(w).Encode(map[string]any{ "errors": z.Issues.Flatten(errs), }) return } fmt.Printf("Creating user: %s (%s)\n", req.Name, req.Email) w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(req) } ``` -------------------------------- ### Go: Type Cast Errors - Coercer Returns Wrong Type in Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/philosophy/panics.md Details type cast errors in Zog's `schema.Parse()` when a custom coercer returns a value of a type different from what the schema expects. This example shows a coercer returning an integer when a string is required, causing a panic. ```go var schema = z.Struct(z.Schema{ "name": z.String(z.WithCoercer(func (v any, ctx z.Ctx) (any, error) { return 1, nil // we are returning an int but the schema is expecting a string })).Required(), }) val := User{ Name: "zog", } schema.Parse(map[string]any{"name": "zog"}, &val) // This will panic because the coercer is returning an int but the schema is expecting a string ``` -------------------------------- ### Reusable Complex Custom Test Function - Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/custom-tests.md Provides an example of creating a reusable complex custom test by encapsulating Zog's `Test` struct within a Go function. This pattern helps in organizing and reusing sophisticated validation logic across different parts of an application. ```go func MyComplexTest() z.Test[*string] { return z.Test{ Func: func (valPtr *string, ctx z.Ctx) { // complex test here } } } ``` -------------------------------- ### Handle and Format Validation Errors in Go Source: https://context7.com/oudwins/zog/llms.txt Demonstrates how to process Zog validation errors using built-in formatting utilities like Flatten, Treeify, and Prettify. It also shows how to access specific issue details such as paths, codes, and original values. ```go import z "github.com/Oudwins/zog" func ValidateUser(data map[string]any) { var user User errs := userSchema.Parse(data, &user) if errs != nil { flat := z.Issues.Flatten(errs) tree := z.Issues.Treeify(errs) pretty := z.Issues.Prettify(errs) } } func HandleErrors(errs z.ZogIssueList) { for _, issue := range errs { pathStr := issue.PathString() code := issue.Code message := issue.Message } } ``` -------------------------------- ### Define Default and Catch Values in Schemas Source: https://context7.com/oudwins/zog/llms.txt Shows how to assign default values for missing fields and define fallback 'catch' values to be used when validation fails, supporting both static values and dynamic functions. ```go var settingsSchema = z.Struct(z.Shape{ "Theme": z.String().Default("light"), "CreatedAt": z.Time().DefaultFunc(func() time.Time { return time.Now() }), }) // Catch fallback on validation failure safeIntSchema := z.Int().GT(0).Catch(1) // Dynamic catch dynamicCatchSchema := z.String().Min(3).CatchFunc(func() string { return fmt.Sprintf("default_%d", time.Now().Unix()) }) ``` -------------------------------- ### Validate slices and collections with Zog Source: https://context7.com/oudwins/zog/llms.txt Shows how to define schemas for slices of primitives or structs, including constraints for length, element existence, and collection size. ```go import z "github.com/Oudwins/zog" tagsSchema := z.Slice(z.String().Required().Min(1)).Min(1, z.Message("At least one tag required")).Max(10) type Item struct { Name string Price float64 } itemSchema := z.Struct(z.Shape{ "Name": z.String().Required(), "Price": z.Float64().Required().GT(0), }) itemsSchema := z.Slice(itemSchema).Min(1).Max(100) numbersSchema := z.Slice(z.Int()).Contains(42) fixedSchema := z.Slice(z.String()).Length(3) ``` -------------------------------- ### Transform Data with Zog Preprocessing Source: https://github.com/oudwins/zog/blob/master/README.md Demonstrates the use of z.Preprocess to manipulate input data before validation, allowing for custom logic like string splitting. ```go var dest []string schema := z.Preprocess(func(data any, ctx z.Ctx) ([]string, error) { s := data.(string) // don't do this, actually check the type return strings.Split(s, ","), nil }, z.Slice(z.String().Trim().Email().Required())) errs := schema.Parse("foo@bar.com,bar@foo.com", &dest) ``` -------------------------------- ### Define Zog Schema and Destination Structs Source: https://github.com/oudwins/zog/blob/master/docs/docs/philosophy/core-design-decisions.md Demonstrates how to define a Zog schema using z.Struct and z.Shape, and illustrates valid versus invalid destination structures. It highlights that Zog will panic if the destination struct does not align with the defined schema fields. ```go var schema = z.Struct(z.Shape{ "name": z.String().Required(), }) // This struct is a valid destination for the schema type User struct { Name string Age int // age will be ignored since it is not a field in the schema } // this struct is not a valid structure for the schema. It is missing the name field. // This will cause Zog to panic in both Parse and Validate mode type User2 struct { Email string Age int } schema.Parse(map[string]any{"name": "zog"}, &User{}) // this will panic even if input data is valid. Because the destination is not a valid structure for the schema schema.Validate(&User2{}) // This will panic because the structure does not match the schema ``` -------------------------------- ### Implementing Custom Transformations Source: https://github.com/oudwins/zog/blob/master/docs/docs/core-concepts/1-anatomy-of-schema.md Shows how to define transformation functions that modify data in place using pointers, including complex struct transformations. ```go type Transform[T any] func(dataPtr T, ctx Ctx) error type User struct { Phone string AreaCode string } z.Struct(z.Shape{ "phone": z.String().Test(...).Transform(func (valPtr *string, ctx z.Ctx) error{ *valPtr = strings.ReplaceAll(*valPtr, " ", "") return nil }), }).Transform(func(dataPtr any, ctx z.Ctx) error { user := dataPtr.(*User) user.AreaCode = user.Phone[:3] user.Phone = user.Phone[3:] return nil }) ``` -------------------------------- ### Configuration Options Source: https://github.com/oudwins/zog/blob/master/docs/docs/reference.md Utility functions for configuring test messages, schema coercion, and execution context behavior. ```go z.Message() z.MessageFunc(fn) z.IssueCode() z.IssuePath() z.WithCoercer(fn) z.WithIssueFormatter(fn) z.WithCtxValue(key, val) ``` -------------------------------- ### Accessing the First Error in Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/migrations/0.21-to-0.22.md Illustrates how to access the first error in the list after the migration to a unified slice-based return type. ```go // Before: first := errs["$first"][0] // After (option 1 - direct): first := errs[0] ``` -------------------------------- ### Implement Custom Validation with Context Source: https://github.com/oudwins/zog/blob/master/docs/docs/advanced/context.mdx Demonstrates how to use the context to retrieve custom data passed during the Parse call and perform conditional validation logic. ```go nameSchema := z.String().Min(3).Test(func(data *string, ctx z.Ctx) (bool) { b := ctx.Get("is_valid").(bool) return b }) nameSchema.Parse("Michael Jackson", &dest, z.WithCtxValue("is_valid", true)) ``` -------------------------------- ### Validate Slices with Zog Source: https://github.com/oudwins/zog/blob/master/docs/docs/reference.md Demonstrates how to validate slice length and content requirements using Zog slice schemas. ```go z.Slice(Int()).Min(5) // validates slice has at least 5 elements z.Slice(Float()).Max(5) // validates slice has at most 5 elements z.Slice(Bool()).Length(5) // validates slice has exactly 5 elements z.Slice(String()).Contains("foo") // validates slice contains the element "foo" ``` -------------------------------- ### Define Custom Primitive Schemas with Generics in Go Source: https://github.com/oudwins/zog/blob/master/docs/docs/custom-schemas.md Demonstrates how to define custom schemas for primitive types (string, int) in Go using Zog's generics. This allows for type-safe schema definitions and usage, enhancing code clarity and reducing errors. It shows defining custom types and constants, creating schema functions, and using these schemas within a struct. ```go // definition in your code type Env string const ( Prod Env = "prod" Dev Env = "env" ) type Status int const ( Active Status = 1 Inactive Status = 0 // default value ) func EnvSchema() *StringSchema[Env] { return z.StringLike[Env]().OneOf([]Env{Prod, Dev}) } // usage type S struct { Environment Env Status Status } schema := z.Struct( z.Shape{ "Environment": EnvSchema(), // All string methods will now be typed to Env type "Status": z.IntLike[Status]().OneOf([]Status{Active, Inactive}), }, ) ```