{"id":47605026,"url":"https://github.com/zoobz-io/check","last_synced_at":"2026-04-01T19:08:31.566Z","repository":{"id":333993607,"uuid":"1139481979","full_name":"zoobz-io/check","owner":"zoobz-io","description":"Fluent validation for Go with struct tag verification","archived":false,"fork":false,"pushed_at":"2026-03-20T02:56:19.000Z","size":80,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-20T05:23:17.555Z","etag":null,"topics":["fluent-api","go","golang","struct-tags","type-safety","validation","zoobzio"],"latest_commit_sha":null,"homepage":"https://check.zoobz.io","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zoobz-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-22T02:36:46.000Z","updated_at":"2026-03-20T02:54:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/zoobz-io/check","commit_stats":null,"previous_names":["zoobzio/check","zoobz-io/check"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/zoobz-io/check","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fcheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fcheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fcheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fcheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zoobz-io","download_url":"https://codeload.github.com/zoobz-io/check/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zoobz-io%2Fcheck/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31291083,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["fluent-api","go","golang","struct-tags","type-safety","validation","zoobzio"],"created_at":"2026-04-01T19:08:30.746Z","updated_at":"2026-04-01T19:08:31.558Z","avatar_url":"https://github.com/zoobz-io.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# check\n\n[![CI Status](https://github.com/zoobz-io/check/workflows/CI/badge.svg)](https://github.com/zoobz-io/check/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/zoobz-io/check/graph/badge.svg?branch=main)](https://codecov.io/gh/zoobz-io/check)\n[![Go Report Card](https://goreportcard.com/badge/github.com/zoobz-io/check)](https://goreportcard.com/report/github.com/zoobz-io/check)\n[![CodeQL](https://github.com/zoobz-io/check/workflows/CodeQL/badge.svg)](https://github.com/zoobz-io/check/security/code-scanning)\n[![Go Reference](https://pkg.go.dev/badge/github.com/zoobz-io/check.svg)](https://pkg.go.dev/github.com/zoobz-io/check)\n[![License](https://img.shields.io/github/license/zoobz-io/check)](LICENSE)\n[![Go Version](https://img.shields.io/github/go-mod/go-version/zoobz-io/check)](go.mod)\n[![Release](https://img.shields.io/github/v/release/zoobz-io/check)](https://github.com/zoobz-io/check/releases)\n\nFluent validation for Go with struct tag verification.\n\n## Usage\n\n```go\ntype User struct {\n    Email    string  `json:\"email\" validate:\"required,email\"`\n    Password string  `json:\"password\" validate:\"required,min=8\"`\n    Name     *string `json:\"name\" validate:\"omitempty,max=100\"`\n    Age      int     `json:\"age\" validate:\"min=13,max=120\"`\n}\n\nfunc (u *User) Validate() error {\n    return check.Check[User](\n        check.Str(u.Email, \"email\").Required().Email().MaxLen(255).V(),\n        check.Str(u.Password, \"password\").Required().MinLen(8).V(),\n        check.OptStr(u.Name, \"name\").MaxLen(100).V(),\n        check.Num(u.Age, \"age\").Between(13, 120).V(),\n    ).Err()\n}\n```\n\n`Check[T]` validates your fields and verifies that every field with a `validate` tag was actually checked. Forget a field? You'll know:\n\n```text\npassword: tagged but not validated (validate: required,min=8)\n```\n\nNo magic, no reflection at validation time—just functions that return validation results.\n\n```go\nr := user.Validate()\nif r.Err() != nil {\n    fmt.Println(r.Err())\n    // email: must be a valid email address; age: must be between 13 and 120\n\n    for _, fe := range check.GetFieldErrors(r) {\n        fmt.Printf(\"%s: %s\\n\", fe.Field, fe.Message)\n    }\n    // email: must be a valid email address\n    // age: must be between 13 and 120\n}\n```\n\nValidation logic lives where you can see it, test it, and refactor it.\n\n## Install\n\n```bash\ngo get github.com/zoobz-io/check\n```\n\nRequires Go 1.24+.\n\n## Fluent Builders\n\nChain validators naturally:\n\n```go\n// Strings\ncheck.Str(email, \"email\").Required().Email().MaxLen(255).V()\n\n// Optional strings (nil skips validation)\ncheck.OptStr(name, \"name\").MaxLen(100).V()\n\n// Numbers\ncheck.Num(age, \"age\").Between(13, 120).V()\n\n// Integers (adds Even, Odd, MultipleOf)\ncheck.Int(count, \"count\").Positive().Even().V()\n\n// Slices with auto-generated field names\ncheck.StrSlice(tags, \"tags\").NotEmpty().MaxItems(10).Each(func(b *check.StrBuilder) {\n    b.MaxLen(50)  // Validates tags[0], tags[1], etc.\n}).V()\n```\n\nConditional validation with `.When()`:\n\n```go\ncheck.Str(password, \"password\").\n    Required().\n    When(requireStrong, func(b *check.StrBuilder) {\n        b.MinLen(12).Match(complexityRegex)\n    }).V()\n```\n\n## Direct Functions\n\nUse validators directly when you don't need the fluent API:\n\n```go\ncheck.All(\n    check.Required(email, \"email\"),\n    check.Email(email, \"email\"),\n    check.Between(age, 13, 120, \"age\"),\n)\n```\n\n## Capabilities\n\n| Category    | Builders                                       | Functions                                                                                    |\n| ----------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------- |\n| Strings     | `Str`, `OptStr`                                | `Required`, `MinLen`, `MaxLen`, `Match`, `Prefix`, `Suffix`, `OneOf`, `Alpha`, `Slug`, etc.  |\n| Numbers     | `Num`, `OptNum`, `Int`, `OptInt`               | `Min`, `Max`, `Between`, `Positive`, `Negative`, `NonZero`, `MultipleOf`, `Percentage`       |\n| Slices      | `Slice`, `OptSlice`, `StrSlice`, `OptStrSlice` | `NotEmpty`, `MinItems`, `Unique`, `ContainsAll`, `Each`, `AllSatisfy`, `Subset`              |\n| Formats     | (via `Str` methods)                            | `Email`, `URL`, `UUID`, `IP`, `CIDR`, `Semver`, `E164`, `CreditCard`, `JSON`, `Base64`       |\n| Comparison  | —                                              | `Equal`, `NotEqual`, `GreaterThan`, `LessThan`, `EqualField`, `GreaterThanField`             |\n| Maps        | —                                              | `NotEmptyMap`, `HasKey`, `HasKeys`, `OnlyKeys`, `EachKey`, `EachMapValue`, `UniqueValues`    |\n| Pointers    | —                                              | `NotNil`, `Nil`, `NilOr`, `RequiredPtr`, `DefaultOr`, `Deref`                                |\n| Time        | —                                              | `Before`, `After`, `InPast`, `InFuture`, `BetweenTime`, `WithinDuration`, `NotWeekend`       |\n| Aggregation | —                                              | `All` (collect all errors), `First` (fail-fast), `Merge`, `Check[T]` (with tag verification) |\n\n## Validation Tracking\n\nCheck tracks which validators were applied to which fields, enabling downstream verification of validation coverage.\n\n```go\nr := check.All(\n    check.Required(email, \"email\"),\n    check.Email(email, \"email\"),\n    check.Between(age, 13, 120, \"age\"),\n)\n\n// Check if specific validators ran\nr.HasValidator(\"email\", \"required\") // true\nr.HasValidator(\"email\", \"email\")    // true\nr.HasValidator(\"age\", \"min\")        // true (Between reports min and max)\nr.HasValidator(\"age\", \"max\")        // true\n\n// Get all validators for a field\nr.ValidatorsFor(\"email\") // []string{\"required\", \"email\"}\n\n// Get all validated fields\nr.Fields() // []string{\"email\", \"age\"}\n\n// Get full tracking map\nr.Applied() // map[string][]string{\"email\": {\"required\", \"email\"}, \"age\": {\"min\", \"max\"}}\n```\n\nThis enables tools to verify that declared validation rules match actual runtime validation.\n\n## Why check?\n\n- **Fluent API** — chain validators, reduce boilerplate\n- **Tag verification** — `Check[T]` catches forgotten fields at runtime\n- **Zero reflection** — validation is function calls, fully visible and debuggable\n- **Type-safe generics** — `Min[T]`, `Between[T]`, `Each[T]` catch type errors at compile time\n- **Composable** — `All()` collects errors, `First()` fails fast, nest them freely\n- **Field-aware errors** — every error knows which field failed and why\n- **Validation tracking** — verify which validators ran on which fields\n\n## Validation as Code\n\nCheck enables a pattern: **validation logic as visible, testable code**.\n\nYour validation rules live in methods alongside your types. They're testable, refactorable, and readable. No tag DSL to learn, no reflection overhead, no magic.\n\n```go\n// Conditional validation — just Go code\nfunc (o Order) Validate() error {\n    validations := []*check.Validation{\n        check.Str(o.ID, \"id\").Required().UUID().V(),\n        check.Num(o.Total, \"total\").Positive().V(),\n    }\n\n    if o.ShipmentType == \"express\" {\n        validations = append(validations,\n            check.Str(o.ExpressCode, \"express_code\").Required().V(),\n        )\n    }\n\n    return check.All(validations...).Err()\n}\n\n// Cross-field validation — just compare values\nfunc (r DateRange) Validate() error {\n    return check.All(\n        check.NotZeroTime(r.Start, \"start\"),\n        check.NotZeroTime(r.End, \"end\"),\n        check.GreaterThanField(r.End, r.Start, \"end\", \"start\"),\n    ).Err()\n}\n\n// Slice element validation — auto-generated field names\nfunc (c Cart) Validate() error {\n    return check.All(\n        check.StrSlice(c.ItemIDs, \"items\").NotEmpty().Each(func(b *check.StrBuilder) {\n            b.Required().UUID()\n        }).V(),\n    ).Err()\n}\n```\n\nThe compiler checks your validation logic. Your IDE can navigate to it. Your tests can exercise it directly.\n\n## Documentation\n\n- [pkg.go.dev reference](https://pkg.go.dev/github.com/zoobz-io/check)\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n## License\n\nMIT License — see [LICENSE](LICENSE) for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoobz-io%2Fcheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzoobz-io%2Fcheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzoobz-io%2Fcheck/lists"}