{"id":19764321,"url":"https://github.com/grahms/godantic","last_synced_at":"2025-07-19T11:02:34.704Z","repository":{"id":52114862,"uuid":"520781315","full_name":"GraHms/godantic","owner":"GraHms","description":"godantic is a Go package that provides functionality for decoding JSON data and validating it against a given object structure. It aims to simplify the process of decoding and validating JSON input in Go applications.","archived":false,"fork":false,"pushed_at":"2025-06-18T08:18:26.000Z","size":703,"stargazers_count":29,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-08T05:09:58.212Z","etag":null,"topics":["golang-package","validation-library"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GraHms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-03T07:32:04.000Z","updated_at":"2025-06-18T08:17:36.000Z","dependencies_parsed_at":"2024-06-19T15:00:30.290Z","dependency_job_id":"e81787a4-1e5b-4da2-98a3-0b0e324e5bc5","html_url":"https://github.com/GraHms/godantic","commit_stats":{"total_commits":3,"total_committers":2,"mean_commits":1.5,"dds":"0.33333333333333337","last_synced_commit":"ffbcca8cf4487f71fea518eef698e5333f23849e"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/GraHms/godantic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GraHms%2Fgodantic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GraHms%2Fgodantic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GraHms%2Fgodantic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GraHms%2Fgodantic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GraHms","download_url":"https://codeload.github.com/GraHms/godantic/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GraHms%2Fgodantic/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264341130,"owners_count":23593298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang-package","validation-library"],"created_at":"2024-11-12T04:13:26.262Z","updated_at":"2025-07-08T20:14:14.660Z","avatar_url":"https://github.com/GraHms.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Godantic\n[![Go Report Card](https://goreportcard.com/badge/github.com/grahms/godantic)](https://goreportcard.com/report/github.com/grahms/godantic)\n[![Go Reference](https://pkg.go.dev/badge/github.com/grahms/godantic.svg)](https://pkg.go.dev/github.com/grahms/godantic)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n[![Tests](https://github.com/grahms/godantic/actions/workflows/tests.yml/badge.svg)](https://github.com/grahms/godantic/actions/workflows/tests.yml)\n[![Code Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen.svg)](#) \u003c!-- substitui com real se tiver cobertura --\u003e\n[![Issues](https://img.shields.io/github/issues/grahms/godantic)](https://github.com/grahms/godantic/issues)\n\nGodantic is a Go package for inspecting and validating JSON-like data against Go struct types and schemas. It provides functionalities for checking type compatibility, structure compatibility, and other validations such as empty string, invalid time, minimum length list checks, regex pattern matching, and format validation.\n\n## Getting Started\n\nInstall the godantic package:\n\n```sh\ngo get github.com/grahms/godantic\n```\n\nThen import it in your Go code:\n\n```go\nimport \"github.com/grahms/godantic\"\n```\n\n## Simple Usage\n\n```go\ntype Person struct {\n    Name *string `json:\"name\" binding:\"required\"`\n    Age  *int    `json:\"age\"`\n}\n\nvar jsonData = []byte(`{\"name\": \"John\", \"age\": 30}`)\nvar person Person\n\nvalidator := godantic.Validate{}\n\nerr := validator.BindJSON(jsonData, \u0026person)\nif err != nil {\n    fmt.Println(err)\n}\n```\n\n## Advanced Usage\n\n- Enum Validation\n\n```go\ntype Person struct {\n    Name *string `json:\"name\" binding:\"required\"`\n    Role *string `json:\"role\" enum:\"admin,user\"`\n}\n\n// Here, the Role field must be either 'admin' or 'user'. If it's not, an error is returned.\n```\n\n- Handling Extra Fields\n\n```go\nvar jsonData = []byte(`{\"name\": \"John\", \"age\": 30, \"extra\": \"extra data\"}`)\nvar person Person\n\nvalidator := godantic.Validate{}\n\nerr := validator.BindJSON(jsonData, \u0026person)\nif err != nil {\n    fmt.Println(err) // This will print an error about the 'extra' field not being valid.\n}\n```\nTo allow unknown keys for a specific field, declare that field in the reference\nmap as `godantic.Object`:\n\n```go\nref := map[string]any{\n    \"name\": \"\",\n    \"meta\": godantic.Object{},\n}\n\nreq := map[string]any{\n    \"name\": \"John\",\n    \"meta\": map[string]any{\"foo\": 1, \"bar\": \"baz\"},\n}\n\n_ = validator.CheckTypeCompatibility(req, ref)\n```\n\n- Custom Error Handling\n\n```go\ntype CustomError struct {\n    ErrType string\n    Message string\n    Path    string\n    err     error\n}\n\nfunc (e *CustomError) Error() string {\n    e.err = errors.New(e.Message)\n    return e.err.Error()\n}\n\n// Now you can create your own error type and return it in your custom validation functions.\n```\n\n- Inspecting and Validating Structs\n\n```go\nvalidator := godantic.Validate{}\nerr := validator.InspectStruct(\u0026myStruct)\nif err != nil {\n    fmt.Println(err)\n}\n```\n\n## Nested Fields \u0026 Objects\n\n```go\ntype Address struct {\n    City  *string `json:\"city\" binding:\"required\"`\n    State *string `json:\"state\" binding:\"required\"`\n}\n\ntype Person struct {\n    Name    *string `json:\"name\" binding:\"required\"`\n    Age     *int    `json:\"age\"`\n    Address *Address `json:\"address\"`\n}\n\nvar jsonData = []byte(`{\n    \"name\": \"John\",\n    \"age\": 30,\n    \"address\": {\n        \"city\": \"New York\",\n        \"state\": \"NY\"\n    }\n}`)\n\nvar person Person\n\nvalidator := godantic.Validate{}\n\nerr := validator.BindJSON(jsonData, \u0026person)\nif err != nil {\n    fmt.Println(err)\n}\n```\n\nIn this example, the `Person` struct has a nested `Address` struct. The `godantic` package will validate the fields of the nested struct as well.\n\n## Lists\n\n```go\ntype Skill struct {\n    Name *string `json:\"name\" binding:\"required\"`\n    Level *int `json:\"level\"`\n}\n\ntype Person struct {\n    Name  *string `json:\"name\" binding:\"required\"`\n    Age   *int    `json:\"age\"`\n    Skills []Skill `json:\"skills\"`\n}\n\nvar jsonData = []byte(`{\n    \"name\": \"John\",\n    \"age\": 30,\n    \"skills\": [\n        {\n            \"name\": \"Go\",\n            \"level\": 5\n        },\n        {\n            \"name\": \"Python\",\n            \"level\": 4\n        }\n    ]\n}`)\n\nvar person Person\n\nvalidator := godantic.Validate{}\n\nerr := validator.BindJSON(jsonData, \u0026person)\nif err != nil {\n    fmt.Println(err)\n}\n```\n\nIn this example, the `Person` struct has a `Skills` field that is a slice of `Skill` structs. The `godantic` package will iterate over the list and validate each object in the list.\n\n## Integration with Web Frameworks\n\n### Using Godantic with Gin\n\nHere's an example of how to use the `godantic` package with the Gin web framework.\n\n```go\npackage main\n\nimport (\n    \"github.com/gin-gonic/gin\"\n    \"github.com/grahms/godantic\"\n    \"net/http\"\n)\n\ntype User struct {\n    Name    *string `json:\"name\" binding:\"required\"`\n    Email   *string `json:\"email\" binding:\"required\"`\n    Age     *int    `json:\"age\"`\n}\n\nfunc main() {\n    r := gin.Default()\n\n    r.POST(\"/user\", func(c *gin.Context) {\n        var user User\n        validator := godantic.Validate{}\n\n        jsonData, err := c.GetRawData()\n        if err != nil {\n            c.JSON(http\n\n.StatusBadRequest, gin.H{\"error\": err.Error()})\n            return\n        }\n\n        err = validator.BindJSON(jsonData, \u0026user)\n        if err != nil {\n            c.JSON(http.StatusBadRequest, gin.H{\"error\": err.Error()})\n            return\n        }\n\n        c.JSON(http.StatusOK, gin.H{\"status\": \"ok\"})\n    })\n\n    r.Run()\n}\n```\n\nIn the example above, instead of using Gin's built-in JSON binding (`c.BindJSON(\u0026user)`), we're using `godantic`'s `BindJSON` function. Here are the advantages:\n\n1. **More control over validation**: `godantic` provides much more control over the validation process compared to Gin's built-in binding. It supports various validation methods and customizations like type compatibility checks, structure compatibility checks, and handling extra fields. You can customize these validation rules based on your needs.\n\n2. **Detailed error reporting**: `godantic` provides detailed error types and messages which can be very useful for debugging and for providing precise error messages to the API users. In contrast, Gin's built-in binding returns a generic \"binding error\".\n\n3. **Enum Validation**: `godantic` supports enum validation, which is not available in Gin's built-in JSON binding.\n\n4. **Nested Fields \u0026 Objects**: `godantic` supports validation for nested fields and objects as well as lists, which provides more flexibility and control compared to Gin's built-in binding.\n\nPlease remember that the Go's `json.Unmarshal` function used by `godantic` doesn't check for additional fields in the JSON input that are not present in the target struct. If you want to disallow additional fields, you might have to implement additional checks.\n\n## Features\n\n- **BindJSON**: Parses and validates JSON data into a provided struct. It performs type checking and structural validation against the expected schema of the provided struct.\n- **InspectStruct**: Iteratively inspects the fields of a struct based on their type and validates them based on certain conditions.\n- **CheckTypeCompatibility**: Checks if two `map[string]interface{}` objects (request and reference data) are compatible in terms of structure and type.\n\n## Error Types\n\n- `REQUIRED_FIELD_ERR`: Triggered when a field marked as required is not provided.\n- `INVALID_ENUM_ERR`: Triggered when a field value is not among the allowed enum values.\n- `INVALID_FIELD_ERR`: Triggered when an invalid field is provided.\n- `TYPE_MISMATCH_ERR`: Triggered when a field is given a value with an invalid type.\n- `SYNTAX_ERR`: Triggered when there is a syntax error in the JSON data.\n- `INVALID_JSON_ERR`: Triggered when the provided data is not valid JSON.\n- `EMPTY_JSON_ERR`: Triggered when the provided JSON data is empty.\n- `INVALID_TIME_ERR`: Triggered when a time.Time field has an invalid time value.\n- `EMPTY_STRING_ERR`: Triggered when a string field is empty.\n- `EMPTY_LIST_ERR`: Triggered when a list field is empty.\n- `INVALID_REGEX_ERR`: Triggered when a field value does not match the required regex pattern.\n- `INVALID_FORMAT_ERR`: Triggered when a field value does not match the required format.\n\n## Format Tags\n\nThe following table lists the supported format tags and their corresponding regular expressions:\n\n| Format Tag          | Description                      | Example Use Case                      |\n|---------------------|----------------------------------|---------------------------------------|\n| email               | Email address format             | Validating user email addresses       |\n| url                 | URL format                       | Validating website URLs               |\n| date                | Date format (YYYY-MM-DD)        | Validating dates in a specific format |\n| time                | Time format (HH:MM:SS)          | Validating times in a specific format |\n| uuid                | UUID format                      | Validating UUIDs                      |\n| ip                  | IP address format                | Validating IPv4 or IPv6 addresses     |\n| credit_card         | Credit card number format        | Validating credit card numbers        |\n| postal_code         | Postal code format               | Validating postal codes               |\n| phone               | Phone number format              | Validating phone numbers              |\n| ssn                 | Social Security Number format    | Validating SSN                        |\n| credit_card_expiry  | Credit card expiry date format  | Validating credit card expiry dates   |\n| latitude            | Latitude format                  | Validating latitude coordinates       |\n| longitude           | Longitude format                 | Validating longitude coordinates      |\n| hex_color           | Hex color format                 | Validating hex color codes            |\n| mac_address         | MAC address format               | Validating MAC addresses              |\n| html_tag            | HTML tag format                  | Validating HTML tags                  |\n| mz-msisdn           | Mozambican phone number format   | Validating Mozambican phone numbers   |\n| mz-nuit             | Mozambican NUIT format           | Validating Mozambican NUIT numbers    |\n\n\n\n## Using the `ignore` Tag\n\nThe `ignore` tag allows you to exclude specific fields from input validation while still retaining them in the struct. This can be useful for fields representing metadata or internal information that shouldn't be validated during input but are required for other purposes.\n\n### Example\n\nConsider a `User` struct with an `ID` field that should be excluded from input validation but retained in the struct for internal use:\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"github.com/grahms/godantic\"\n)\n\ntype User struct {\n    ID        int    `json:\"id\" binding:\"ignore\"` // ID field is ignored during input validation\n    FirstName string `json:\"first_name\" binding:\"required\"`\n    LastName  string `json:\"last_name\" binding:\"required\"`\n    Email     string `json:\"email\" binding:\"required\" format:\"email\"`\n    // Other fields...\n}\n\nfunc main() {\n    // Example JSON data representing user input\n    jsonData := []byte(`{\n        \"first_name\": \"John\",\n        \"last_name\": \"Doe\",\n        \"email\": \"john.doe@example.com\"\n        // No \"id\" field included\n    }`)\n\n    // Create a new instance of the validator\n    validator := godantic.Validate{}\n\n    // Create an instance of the User struct\n    var user User\n\n    // Bind and validate the JSON data against the User struct\n    err := validator.BindJSON(jsonData, \u0026user)\n    if err != nil {\n        fmt.Println(err)\n        return\n    }\n\n    // Validation successful, process the user data\n    fmt.Printf(\"User ID: %d\\n\", user.ID) // ID is still accessible despite being ignored during validation\n    fmt.Printf(\"Name: %s %s\\n\", user.FirstName, user.LastName)\n    fmt.Printf(\"Email: %s\\n\", user.Email)\n}\n```\n\nIn this example:\n\n- The `ID` field represents a unique identifier for the user and is marked with the `ignore` tag.\n- Despite being ignored during validation, the `ID` field remains accessible in the `User` struct after validation, allowing you to utilize it for internal operations or data processing.\n\n\n---\n\n## 📐 Numeric \u0026 Decimal Constraints\n\n`godantic` supports advanced validation for numeric and decimal fields using struct tags. These rules enable expressive, type-safe constraints on your data models.\n\n### 🔢 `min` and `max` (generic)\n\nUsed to validate:\n- String length\n- Slice/array length\n- Numeric values\n\n```go\ntype User struct {\n  Name  *string `json:\"name\" min:\"3\" max:\"50\"`       // between 3 and 50 characters\n  Tags  *[]int  `json:\"tags\" min:\"1\" max:\"5\"`         // between 1 and 5 items\n  Age   *int    `json:\"age\" min:\"18\" max:\"60\"`        // between 18 and 60 years\n}\n```\n\n---\n\n### ⚖️ `gt`, `ge`, `lt`, `le` (value bounds)\n\nUsed to enforce strict or inclusive numeric constraints.\n\n| Tag  | Meaning                        |\n|------|--------------------------------|\n| `gt` | value must be **greater than** |\n| `ge` | value must be **≥**            |\n| `lt` | value must be **less than**    |\n| `le` | value must be **≤**            |\n\n```go\ntype Product struct {\n  Price *float64 `json:\"price\" gt:\"0\"`     // must be greater than 0\n  Stock *int     `json:\"stock\" le:\"1000\"`  // must be ≤ 1000\n}\n```\n\n---\n\n### 🎯 `multiple_of`\n\nEnsures the value is a multiple of a specified number.\n\n```go\ntype Payment struct {\n  Amount *float64 `json:\"amount\" multiple_of:\"0.05\"` // e.g. currency in increments of 0.05\n}\n```\n\n---\n\n### 🧮 `max_digits` \u0026 `decimal_places`\n\nValidates decimal precision:\n\n| Tag              | Description                                                       |\n|------------------|-------------------------------------------------------------------|\n| `max_digits`     | Max total digits (excluding leading zero, includes decimals)      |\n| `decimal_places` | Max number of digits after the decimal point                      |\n\n```go\ntype Invoice struct {\n  Total *float64 `json:\"total\" max_digits:\"6\" decimal_places:\"2\"` // e.g. 9999.99\n}\n```\n\n---\n\n### ☢️ `allow_inf_nan`\n\nAllows `+Inf`, `-Inf`, and `NaN` values for floating point numbers.\n\n```go\ntype Reading struct {\n  Value *float64 `json:\"value\" allow_inf_nan:\"true\"`\n}\n```\n\n\u003e 🔒 By default, `inf` and `NaN` are **not allowed**.\n\n---\n\n\n\n## Conditional Validation Based on Enum Values\n\n`godantic` allows you to apply **conditional validation rules** based on the values of other fields. This is done using the `when` tag.\n\n### **1️⃣ Basic Conditional Validation**\nYou can specify that a field should only be validated when another field has a specific value.\n\n#### **Example: Requiring a field when `context.type=organization`**\n```go\ntype Context struct {\n    Type *string `json:\"type\" enum:\"individual,organization\"`\n}\n\ntype User struct {\n    RegNo *string `json:\"reg_no\" when:\"context.type=organization;binding=required\"`\n}\n```\n\n✅ **If `context.type` is `\"organization\"`, `reg_no` is required.**  \n❌ **If `context.type` is `\"individual\"`, `reg_no` is ignored.**\n\n#### **Valid JSON Input**\n```json\n{\n  \"context\": { \"type\": \"organization\" },\n  \"user\": { \"reg_no\": \"56789\" }\n}\n```\n\n✅ **Passes validation because `reg_no` is provided for `organization`.**\n\n---\n\n### **2️⃣ Invalid Case: Missing `reg_no` When Type is `organization`**\n```json\n{\n  \"context\": { \"type\": \"organization\" },\n  \"user\": {}\n}\n```\n❌ **Fails validation with error:**\n```\nField \u003cuser.reg_no\u003e is required when context.type=organization\n```\n\n---\n\n### **3️⃣ Multiple Conditions**\nYou can require a field **only when multiple conditions are met.**\n\n#### **Example: Requiring `vat_number` when `context.type=business` and `country=EU`**\n```go\ntype Context struct {\n    Type    *string `json:\"type\" enum:\"individual,business\"`\n    Country *string `json:\"country\" enum:\"EU,US\"`\n}\n\ntype Business struct {\n    VATNumber *string `json:\"vat_number\" when:\"context.type=business;context.country=EU;binding=required\"`\n}\n```\n\n✅ **If `context.type` is `\"business\"` and `context.country` is `\"EU\"`, `vat_number` is required.**  \n❌ **If `context.type` is `\"individual\"`, `vat_number` is ignored.**\n\n#### **Valid JSON**\n```json\n{\n  \"context\": { \"type\": \"business\", \"country\": \"EU\" },\n  \"business\": { \"vat_number\": \"EU123456\" }\n}\n```\n\n---\n\n### **4️⃣ Allowed Operators for Conditions**\n| **Operator** | **Example** | **Meaning** |\n|-------------|------------|-------------|\n| `=` | `context.type=business` | Field must be equal to value |\n\n\n---\n\n## **Why Use Conditional Validation?**\n✅ **Simplifies complex validation logic**  \n✅ **Eliminates unnecessary validation** when conditions aren’t met  \n✅ **Supports dynamic rules based on input data**\n\n---\n\n🚀 **Now you can enforce conditional validation effortlessly!** 🚀\n\n\n## ✅ Custom Validation Tags (`validate`)\n\nGodantic allows you to register custom validation functions tied to specific tag names. These functions give you full control over domain-specific validations, and they integrate seamlessly into your validation flow.\n\n### 🔧 Registering a Custom Validator\n\nUse `RegisterCustom` to attach your custom validation logic to a tag:\n\n```go\ngodantic.RegisterCustom[string](\"starts_with_A\", func(val string, path string) *godantic.Error {\n\tif !strings.HasPrefix(val, \"A\") {\n\t\treturn \u0026godantic.Error{\n\t\t\tErrType: \"STARTS_WITH_A_ERR\",\n\t\t\tPath:    path,\n\t\t\tMessage: fmt.Sprintf(\"The field \u003c%s\u003e must start with 'A'\", path),\n\t\t}\n\t}\n\treturn nil\n})\n```\n\n\u003e ✅ The generic type `[string]` indicates the expected value type for the validation. The function receives the field value and the full path of the field in the struct.\n\n---\n\n### 📌 Applying the Validator to a Struct Field\n\n```go\ntype User struct {\n\tUsername *string `json:\"username\" validate:\"starts_with_A\"`\n}\n```\n\nWhen you call `Validate.InspectStruct(\u0026User{})` or `Validate.BindJSON`, the custom validator will automatically be invoked.\n\n---\n\n### 🧩 Using Multiple Custom Tags\n\nYou can apply multiple custom validations on the same field by separating them with commas:\n\n```go\ntype Product struct {\n\tCode *string `json:\"code\" validate:\"starts_with_A,min_len_3\"`\n}\n```\n\nAll validators (`starts_with_A` and `min_len_3`) will be executed in order. If any of them return an error, validation will fail.\n\n---\n\n### 🧠 Validators by Type\n\nGodantic supports type-safe validation using Go generics. For example, to validate integers:\n\n```go\ngodantic.RegisterCustom[int](\"positive\", func(val int, path string) *godantic.Error {\n\tif val \u003c= 0 {\n\t\treturn \u0026godantic.Error{\n\t\t\tErrType: \"POSITIVE_ERR\",\n\t\t\tPath:    path,\n\t\t\tMessage: fmt.Sprintf(\"The field \u003c%s\u003e must be a positive number\", path),\n\t\t}\n\t}\n\treturn nil\n})\n```\n\n```go\ntype Invoice struct {\n\tAmount *int `json:\"amount\" validate:\"positive\"`\n}\n```\n\n---\n\n### 🛡️ Safety and Design\n\n- You don't need to manually add the `Path` inside the error — Godantic will do it for you if it’s missing.\n- If the field type doesn't match the registered validator's type, the validator is skipped without causing panic.\n\n---\n\n### ✅ Best Practices\n\n- Use descriptive tag names: `min_len_5`, `email_domain_gov`, `alphanumeric_only`, etc.\n- Register all custom validators once during app initialization (`init()` or startup function).\n- Combine with built-in tags like `binding:\"required\"`, `format:\"email\"`, `when:\"...\"`, and `enum:\"...\"` for expressive rules.\n\n---\n## 🔌 Plugin-Based Validation \n\nGodantic supports a powerful **interface-based validation mechanism** that allows you to embed custom logic inside your struct types using the `ValidationPlugin` interface.\n\n### ✨ What is a Plugin?\n\nA Plugin is any struct that implements the following interface:\n\n```go\ntype ValidationPlugin interface {\n\tValidate() *godantic.Error\n}\n```\n\nGodantic will **automatically detect** structs that implement this interface and **invoke the `Validate()` method** during the validation cycle — whether the struct is a root object, nested field, or an item in a list.\n\n---\n\n### 🧪 Example: Basic Plugin\n\n```go\ntype Password struct {\n\tValue *string `json:\"value\"`\n}\n\nfunc (p Password) Validate() *godantic.Error {\n\tif p.Value == nil || len(*p.Value) \u003c 8 {\n\t\treturn \u0026godantic.Error{\n\t\t\tErrType: \"WEAK_PASSWORD\",\n\t\t\tMessage: \"Password must be at least 8 characters long\",\n\t\t}\n\t}\n\treturn nil\n}\n```\n\nThen use it in your main struct:\n\n```go\ntype User struct {\n\tUsername *string  `json:\"username\" binding:\"required\"`\n\tPassword *Password `json:\"password\"` // Plugin validation will be triggered\n}\n```\n\nGodantic will automatically call `Password.Validate()` when you validate the `User` struct.\n\n---\n\n### 📦 Nested Plugin Support\n\nGodantic supports plugins **recursively**, meaning:\n\n- Nested objects\n- Elements within slices\n- Pointers or non-pointers\n\nAll are handled correctly.\n\n#### Example:\n\n```go\ntype Role struct {\n\tName string `json:\"name\"`\n}\n\nfunc (r Role) Validate() *godantic.Error {\n\tif r.Name != \"admin\" \u0026\u0026 r.Name != \"user\" {\n\t\treturn \u0026godantic.Error{\n\t\t\tErrType: \"INVALID_ROLE\",\n\t\t\tMessage: fmt.Sprintf(\"Role \u003c%s\u003e is not allowed\", r.Name),\n\t\t}\n\t}\n\treturn nil\n}\n\ntype User struct {\n\tRoles []Role `json:\"roles\"` // Each Role will be validated using its Validate method\n}\n```\n\n---\n\n### 🧠 Why Use Plugins?\n\n- When logic is too complex for struct tags\n- When validation depends on multiple fields\n- When you want reusable, encapsulated validation units\n- When you want full control over the error being returned\n\n---\n\n### 💡 Good to Know\n\n- Plugin logic runs **after tag validations** (e.g., `binding`, `format`, `regex`).\n- If the plugin returns an error **without a path**, Godantic won’t add one. You should provide the `Path` in the error when relevant.\n- Plugin validation is supported for both **pointer** and **non-pointer** struct types.\n\n---\n\n\n## 🔄 Dynamic Field Validation\n\nIn many applications, some fields are **not strictly typed at compile time** — especially when you're building form-like schemas, dynamic inputs, or polymorphic models.\n\nGodantic solves this elegantly using the `DynamicFieldsValidator` interface.\n\n---\n\n### ✨ What is a Dynamic Field?\n\nA dynamic field is one whose **value, name, and type** are **determined at runtime**, and needs to be validated **accordingly**.\n\nTo support this, implement the following interface:\n\n```go\ntype DynamicFieldsValidator interface {\n\tGetValue() any          // The actual value\n\tGetValueType() string   // Expected type: \"string\", \"float\", \"boolean\", \"integer\"\n\tGetAttribute() string   // The name/path for error reporting\n}\n```\n\nGodantic will automatically invoke your implementation and validate the dynamic value.\n\n---\n\n### ✅ Supported Value Types\n\n| `GetValueType()` | Validated As...       |\n|------------------|------------------------|\n| `\"string\"`       | Must be a Go `string` |\n| `\"float\"`        | Must be a `float64`   |\n| `\"boolean\"`      | Must be a `bool`      |\n| `\"integer\"`      | Must be an `int` or castable `float64` |\n| `\"numeric\"`      | Alias for `\"integer\"` |\n\n---\n\n### 🧪 Example: Simple Dynamic Field\n\n```go\ntype MyDynamicField struct {\n\tValue     interface{} `json:\"value\"`\n\tValueType string      `json:\"valueType\" enums:\"string,integer,boolean\"`\n\tAttribute string      `json:\"attribute\"`\n}\n\nfunc (mdf MyDynamicField) GetValue() any        { return mdf.Value }\nfunc (mdf MyDynamicField) GetValueType() string { return mdf.ValueType }\nfunc (mdf MyDynamicField) GetAttribute() string { return mdf.Attribute }\n```\n\n```go\ntype Request struct {\n\tField MyDynamicField `json:\"field\"`\n}\n```\n\n```json\n{\n  \"field\": {\n    \"value\": 42,\n    \"valueType\": \"integer\",\n    \"attribute\": \"age\"\n  }\n}\n```\n\nGodantic will automatically validate the field value based on the declared type (`\"integer\"` in this case).\n\n---\n\n### 🧪 Example: With Array of Dynamic Fields\n\n```go\ntype Request struct {\n\tFields []MyDynamicField `json:\"fields\"`\n}\n```\n\nEach element in the list will be validated using its dynamic type at runtime.\n\n---\n\n### ❌ Example: Invalid Type\n\n```json\n{\n  \"field\": {\n    \"value\": \"not a number\",\n    \"valueType\": \"integer\",\n    \"attribute\": \"age\"\n  }\n}\n```\n\n✅ Error:\n```\nInvalid value type for field 'age'. Expected numeric value.\n```\n\n---\n\n### 💡 Why Use Dynamic Fields?\n\n- You're building a **form builder**, **rule engine**, or **API that accepts generic inputs**.\n- You want validation **without knowing types at compile time**.\n- You need to enforce types dynamically **based on metadata**.\n\n---\n\n### 💬 Notes\n\n- Works for both **pointer** and **non-pointer** values.\n- Integrates seamlessly into nested objects and lists.\n- Errors are detailed and reference the provided `attribute` for clarity.\n\n---\n\n\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## License\n\nThis project is licensed under the MIT License.\n\n\nThis README.md includes detailed information about how to use Godantic, including simple and advanced usage examples, integration with web frameworks, features, error types, supported format tags, and more. If you have any further updates or modifications, please let me know!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrahms%2Fgodantic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrahms%2Fgodantic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrahms%2Fgodantic/lists"}