{"id":36486488,"url":"https://github.com/golodash/galidator","last_synced_at":"2026-01-12T01:51:46.496Z","repository":{"id":59044160,"uuid":"525040743","full_name":"golodash/galidator","owner":"golodash","description":"Galidator is a validator for golang which provides a general use case approach for validation purposes.","archived":false,"fork":false,"pushed_at":"2025-09-26T14:21:59.000Z","size":230,"stargazers_count":80,"open_issues_count":1,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-26T16:19:13.162Z","etag":null,"topics":["galidator","go","golang","validation","validator"],"latest_commit_sha":null,"homepage":"","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/golodash.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.rst","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-08-15T15:31:33.000Z","updated_at":"2025-09-26T14:22:02.000Z","dependencies_parsed_at":"2024-05-07T15:47:37.598Z","dependency_job_id":"3606f929-4050-49f9-b025-504650f9615d","html_url":"https://github.com/golodash/galidator","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"purl":"pkg:github/golodash/galidator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golodash%2Fgalidator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golodash%2Fgalidator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golodash%2Fgalidator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golodash%2Fgalidator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/golodash","download_url":"https://codeload.github.com/golodash/galidator/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/golodash%2Fgalidator/sbom","scorecard":{"id":434908,"data":{"date":"2025-08-11","repo":{"name":"github.com/golodash/galidator","commit":"7fa740823ad0b674b15fd428b8dcc1074e604f15"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":5,"reason":"7 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/golodash/galidator/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/golodash/galidator/main.yml/main?enable=pin","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"21 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-3vp4-m3rf-835h","Warn: Project is vulnerable to: GO-2023-1737 / GHSA-2c4m-59x9-fr2g","Warn: Project is vulnerable to: GO-2021-0356 / GHSA-8c26-wmh5-6g9v","Warn: Project is vulnerable to: GO-2024-2961","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GO-2022-0288","Warn: Project is vulnerable to: GO-2022-0969 / GHSA-69cg-p879-7622","Warn: Project is vulnerable to: GO-2022-1144 / GHSA-xrjj-mj9h-534m","Warn: Project is vulnerable to: GO-2023-1571 / GHSA-vvpx-j8f3-3w6h","Warn: Project is vulnerable to: GO-2023-1988 / GHSA-2wrh-6pvc-2jm9","Warn: Project is vulnerable to: GO-2023-2102 / GHSA-4374-p667-p6c8","Warn: Project is vulnerable to: GHSA-qppj-fm5r-hxr3","Warn: Project is vulnerable to: GO-2024-2687 / GHSA-4v7x-pqxf-cx7m","Warn: Project is vulnerable to: GO-2024-3333","Warn: Project is vulnerable to: GO-2025-3503 / GHSA-qxp5-gwg8-xv66","Warn: Project is vulnerable to: GO-2025-3595 / GHSA-vvgc-356p-c3xw","Warn: Project is vulnerable to: GO-2022-0493 / GHSA-p782-xgp4-8hr8","Warn: Project is vulnerable to: GO-2022-1059 / GHSA-69ch-w2m2-3vjp","Warn: Project is vulnerable to: GO-2024-2611 / GHSA-8r3f-844c-mc37"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T04:22:17.768Z","repository_id":59044160,"created_at":"2025-08-19T04:22:17.768Z","updated_at":"2025-08-19T04:22:17.768Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28331258,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T00:36:25.062Z","status":"ssl_error","status_checked_at":"2026-01-12T00:36:15.229Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["galidator","go","golang","validation","validator"],"created_at":"2026-01-12T01:51:46.401Z","updated_at":"2026-01-12T01:51:46.483Z","avatar_url":"https://github.com/golodash.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Galidator\n\nGalidator provides general use case for validation purpose.\\\nJust simply create a validator and validate your data with it.\\\nEither it returns `nil` which means that data is valid and your rules all passed or not which means that there\nis/are problem/problems with passed data and validation has failed.\n\n## Installation\n\nJust use `go get` for installation:\n\n```\ngo get github.com/golodash/galidator/v2\n```\n\nAnd then just import the package into your own code.\n\n```go\nimport \"github.com/golodash/galidator/v2\"\n```\n\n## Generator\n\n### What is a Generator?\n\nGenerator is a validator generator which creates them under some common circumstances.\\\nFor example, with `generator.CustomMessages` method you can change default error messages of rules for every other validator that is gonna get created with this generator.\n\nWith this mechanism, you can change some default behavior even before attempting to create your validator.\n\n### How to Create A Generator?\n\n```go\nvar g = galidator.NewGenerator()\nor\nvar g = galidator.New()\nor\nvar g = galidator.G()\n```\n\nAll three does the same.\n\n## Validator\n\n### What is a Validator?\n\nValidator is a `galidator.Validator` interface that gets created under some circumstances that its generator defines + common environmental variables of galidator defines + your specified rules.\n\n### How to Create a Validator?\n\nTo create a validator, first you need to create a unique generator instance and then use generator to call a method to create your validator.\n\n1. `Validator(input interface{}, messages ...Messages) Validator`:\n   1. `input` can be a `ruleSet`. (which gets created by `generator.R() or generator.RuleSet()`)\\\n\tExample down here accepts just an email string:\n\t```go\n\tvar g = galidator.G()\n\tvar validator = g.Validator(g.R().Email())\n\t```\n   2. `input` can be a `struct instance` with tags that define rules on every field.\\\n    Example down here accepts a map or a struct which has a `Email` key and a value which is a valid email:\n\t```go\n\ttype user struct {\n\t\tEmail string `galidator:\"email\"` // instead of `galidator:\"email\"`, `g:\"email\"` can be used\n\t}\n\tvar g = galidator.G()\n\tvar validator = g.Validator(user{})\n\t```\n   3. `messages` input type is obvious and is used to replace common error messages on rules for just this validator.\n\n2. `ComplexValidator(rules Rules, messages ...Messages) Validator`:\n   - Generates a struct/map validator.\\\n\tMostly used for complex scenarios that start with a struct or map view.\n\t```go\n\tvar g = galidator.G()\n\tvar validator = g.ComplexValidator(galidator.Rules{\n\t\t\"Name\":        g.RuleSet(\"name\").Required(),\n\t\t\"Description\": g.RuleSet(\"description\").Required(),\n\t})\n\t```\n\n### How to Validate?\n\nSimply just create your validator with one of the top discussed methods and then:\n\n```go\nvar g = galidator.G()\nvar emailValidator = g.Validator(g.R().Email())\n\nfunc main() {\n\tinput1 := \"valid@email.com\"\n\tinput2 := \"invalidEmail.com\"\n\n\toutput1 := emailValidator.Validate(context.TODO(), input1)\n\toutput2 := emailValidator.Validate(context.TODO(), input2)\n\n\tfmt.Println(output1)\n\tfmt.Println(output2)\n}\n```\n\noutput:\n```\n\u003cnil\u003e\n[not a valid email address]\n```\n\nAnd that's it, just to get better, see more examples down here.\n\n## What is the Usecase of Sending a context to Validate function?\n\nIn web development, sometimes we need to share some data with our custom validators and this is the way we do it, we record it in the context and send it to the validator which can read the sent data in out custom validators by calling `ctx.Value(key)` method.\n\n# Just For [Gin](https://github.com/gin-gonic/gin) Users\n\n## 1. Use Galidator Just to Customize [Gin](https://github.com/gin-gonic/gin)'s Bind Method Error Outputs\n\nYou can choose not to use galidator and it's validation process but instead use `Bind` method of [Gin](https://github.com/gin-gonic/gin) or other acronym's for `Bind` like: `BindJson` for validation process and just use galidator to change output error messages of it.\n\nExample of using galidator inside a gin project:\n\n```go\ntype login struct {\n\tUsername string `json:\"username\" binding:\"required\" required:\"$field is required\"`\n\tPassword string `json:\"password\"`\n}\n\nvar (\n\tg = galidator.G()\n\tvalidator = g.Validator(login{})\n)\n\nfunc test(c *gin.Context) {\n\treq := \u0026login{}\n\n\t// Parse json\n\tif err := c.BindJSON(req); err != nil {\n\t\tc.JSON(400, gin.H{\n\t\t\t// This is the part which generates that output\n\t\t\t\"message\": validator.DecryptErrors(err),\n\t\t})\n\t\treturn\n\t}\n\n\tc.JSON(200, gin.H{\n\t\t\"good\": 200,\n\t})\n}\n\nfunc main() {\n\tr := gin.Default()\n\tr.POST(\"/\", test)\n\tr.Run(\"127.0.0.1:3000\")\n}\n```\n\nIf you don't send `username` or send it empty in json request body, this message returns:\n```\n{\"message\":{\"username\":\"username is required\"}}\n```\n\n**Note**: In cases which there is a conflict of names for rule messages(like `json`, `json` tag is used for output in json and if you want to add error message of json for it, you can't use `json` tag, so the solution is to use `_json` tag)\n\nExample:\n\n```go\ntype login struct {\n\tField string `json:\"field\" binding:\"required,json\" _json:\"$field is not json\"`\n}\n```\n\n## 2. Translate Error Output to Different Languages in [Gin]((https://github.com/gin-gonic/gin))\n\nIf you need to translate output error messages for different languages in a gin project, use this template:\n\n```go\ntype login struct {\n\tUsername string `json:\"username\" g:\"required\" required:\"$field is required\"`\n\tPassword string `json:\"password\"`\n}\n\nvar (\n\tg            = galidator.New()\n\tvalidator    = g.Validator(login{})\n\t// Persian Language Dictionary\n\tfaDictionary = map[string]string{\n\t\t\"$field is required\": \"$field نمیتواند خالی باشد\",\n\t}\n)\n\n// Persian Language Translator\nfunc PersianTranslator(input string) string {\n\tif translated, ok := faDictionary[input]; ok {\n\t\treturn translated\n\t}\n\treturn input\n}\n\n// Middleware that assigns a translator requested by user\nfunc customizeTranslator(c *gin.Context) {\n\tlanguageCode := c.GetHeader(\"Accept-Language\")\n\tif languageCode == \"fa\" {\n\t\tc.Set(\"translator\", PersianTranslator)\n\t} else {\n\t\tc.Set(\"translator\", func(input string) string { return input })\n\t}\n\tc.Next()\n}\n\n// Main Handler\nfunc loginHandler(c *gin.Context) {\n\treq := \u0026login{}\n\ttranslator := c.MustGet(\"translator\").(func(string) string)\n\n\t// Parse json\n\tif err := c.BindJSON(req); err != nil {\n\t\tc.JSON(400, gin.H{\n\t\t\t\"message\": \"bad json\",\n\t\t})\n\t\treturn\n\t}\n\n\t// Validation\n\tif errors := validator.Validate(context.TODO(), req, translator); errors != nil {\n\t\tc.JSON(400, gin.H{\n\t\t\t\"errors\":  errors,\n\t\t\t\"message\": \"bad inputs\",\n\t\t})\n\t\treturn\n\t}\n\n\tc.JSON(200, gin.H{\n\t\t\"good\": 200,\n\t})\n}\n\nfunc main() {\n\tr := gin.Default()\n\tgroupWithMiddleware := r.Group(\"/\", customizeTranslator)\n\tgroupWithMiddleware.POST(\"/\", loginHandler)\n\tr.Run(\"127.0.0.1:3000\")\n}\n```\n\nNow if you make a post request to http://127.0.0.1:3000 url when having `Accept-Language` header with `fa` value assigned to it, and in request body do not specify username field or specify it's value as an empty string, this will be the output:\n\n```\n{\"errors\":{\"username\":[\"username نمیتواند خالی باشد\"]},\"message\": \"bad inputs\"}\n```\n\n## 3. Making Ease of PATCH method with Galidator in [Gin]((https://github.com/gin-gonic/gin))\n\n1. Make all your field types pointer. (string -\u003e *string)\n2. Use `SetDefaultOnNil` method which is accessible from a `Validator` instance.\n   - Have in mind to pass pointer to a struct variable into `SetDefaultOnNil` method.\n3. Done... items are nil if user did not send them to api and will be filled with default values which programmer passed them.\n\n```go\ntype article struct {\n\tTitle   *string `json:\"title\"`\n\tContent *string `json:\"content\"`\n}\n\nvar (\n\ttitle    = \"This is first\"\n\tcontent  = \"This is the content\"\n\tarticles = []article{\n\t\t{Title: \u0026title, Content: \u0026content},\n\t}\n\tg         = galidator.G()\n\tvalidator = g.Validator(article{})\n)\n\nfunc patchArticle(c *gin.Context) {\n\treq := \u0026article{}\n\tid, _ := strconv.Atoi(c.Param(\"id\"))\n\tdefaults := articles[id]\n\n\tc.BindJSON(req)\n\tif err := validator.Validate(context.TODO(), req); err == nil {\n\t\t// This is the part to set default value for nil fields\n\t\tvalidator.SetDefaultOnNil(req, defaults)\n\t\t// This is update action\n\t\tarticles[id] = *req\n\t} else {\n\t\tc.JSON(400, gin.H{\n\t\t\t\"message\": \"error in validation\",\n\t\t})\n\t}\n\n\tc.JSON(200, gin.H{\n\t\t\"good\": 200,\n\t\t\"data\": req,\n\t})\n}\n\nfunc main() {\n\tr := gin.Default()\n\tr.PATCH(\"/comments/:id\", patchArticle)\n\tr.Run(\"127.0.0.1:3000\")\n}\n```\n\n# Examples\n\n## Simple Usage(Register a User)\n\nLets validate a register form:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.ComplexValidator(galidator.Rules{\n\t\t\"Username\": g.R(\"username\").Required().Min(3).Max(32),\n\t\t\"Password\": g.R(\"password\").Required().Password(),\n\t\t\"Email\":    g.R(\"email\").Required().Email(),\n\t})\n\n\tuserInput := map[string]string{\n\t\t\"username\": \"DoctorMK\",\n\t\t\"password\": \"123456789\",\n\t\t\"email\":    \"DoctorMK@gmail.com\",\n\t}\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\nmap[password:[password must be at least 8 characters long and contain one lowercase, one uppercase, one special and one number character]]\nfalse\n```\n\nWe can even validate a struct by the same validator and get the same result:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\ntype Person struct {\n\tUsername string\n\tPassword string\n\tEmail    string\n}\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(galidator.Rules{\n\t\t\"Username\": g.R(\"username\").Required().Min(3).Max(32),\n\t\t\"Password\": g.R(\"password\").Required().Min(5).Password(),\n\t\t\"Email\":    g.R(\"email\").Required().Email(),\n\t})\n\n\tuserInput := Person{\n\t\tUsername: \"DoctorMK\",\n\t\tPassword: \"123456789\",\n\t\tEmail:    \"DoctorMK@gmail.com\",\n\t}\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOr we can even create the same validator by defining some struct tags.\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\ntype Person struct {\n\tUsername string `json:\"username\" g:\"required,min=3,max=32\"`\n\tPassword string `json:\"password\" g:\"required,min=5,password\"`\n\tEmail    string `json:\"email\" g:\"required,email\"`\n}\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(Person{})\n\n\tuserInput := Person{\n\t\tUsername: \"DoctorMK\",\n\t\tPassword: \"123456789\",\n\t\tEmail:    \"DoctorMK@gmail.com\",\n\t}\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\n## Receive a list of users\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\ntype Person struct {\n\tUsername string `json:\"username\" g:\"required,min=3,max=32\"`\n\tPassword string `json:\"password\" g:\"required,min=5,password\" password:\"$field failed\"`\n\tEmail    string `json:\"email\" g:\"required,email\"`\n}\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator([]Person{})\n\n\tuserInput := []Person{\n\t\t{\n\t\t\tUsername: \"DoctorMK\",\n\t\t\tPassword: \"123456789\",\n\t\t\tEmail:    \"DoctorMK@gmail.com\",\n\t\t},\n\t\t{\n\t\t\tUsername: \"Asghar\",\n\t\t\tPassword: \"123456789mH!@\",\n\t\t\tEmail:    \"Doctors@gmail.com\",\n\t\t},\n\t}\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\nmap[0:map[password:[password failed]]]\nfalse\n```\n\nWe can create the same validator without tags too:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(g.R().Children(\n\t\tg.R().Complex(galidator.Rules{\n\t\t\t\"Username\": g.R(\"username\").Required().Min(3).Max(32),\n\t\t\t\"Password\": g.R(\"password\").Required().Password().SpecificMessages(galidator.Messages{\"password\": \"$field failed\"}),\n\t\t\t\"Email\":    g.R(\"email\").Required().Email(),\n\t\t})))\n\n\tuserInput := []map[string]string{\n\t\t{\n\t\t\t\"username\": \"DoctorMK\",\n\t\t\t\"password\": \"123456789\",\n\t\t\t\"email\":    \"DoctorMK@gmail.com\",\n\t\t},\n\t\t{\n\t\t\t\"username\": \"Asghar\",\n\t\t\t\"password\": \"123456789mH!@\",\n\t\t\t\"email\":    \"Doctors@gmail.com\",\n\t\t},\n\t}\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\n## OR\n\nIn this example, input has to be either an email address or just a string longer equal to 5 characters or both.\n\nThis example OR operator in struct tags can be used like: `g:\"required,or=email|string+min=5\"`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(g.R().Required().OR(g.R().Email(), g.R().String().Min(5)))\n\n\tinput := \"m@g.com\"\n\terrors := validator.Validate(context.TODO(), input)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\n\u003cnil\u003e\ntrue\n```\n\n## XOR\n\nIn this example, input has to be either an email address or phone number.\n\nThis example XOR operator in struct tags can be used like: `g:\"required,xor=email|phone\"`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(g.R().Required().XOR(g.R().Email(), g.R().Phone()))\n\n\tinput := \"m@g.com\"\n\terrors := validator.Validate(context.TODO(), input)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\n\u003cnil\u003e\ntrue\n```\n\n## WhenExistAll - WhenExistOne\n\nIn this example, if two other struct fields(`Username` and `Password`) are not empty,\nnil or zero, field will act as a required field and all of its rules will get checked.\\\nOtherwise, if empty, nil or zero value get passed, because by default fields are\noptional, it does not check other defined rules and assume it passed.\\\nYou can use this in tags like: `g:\"when_exist_all=Username\u0026Password,string\" when_exist_all:\"when_exist_all failed\"`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New()\n\tv := g.ComplexValidator(galidator.Rules{\n\t\t\"Username\": g.R(\"username\").String(),\n\t\t\"Password\": g.R(\"password\").String(),\n\t\t\"Data\":     g.R(\"data\").WhenExistAll(\"Username\", \"Password\").String().SpecificMessages(galidator.Messages{\"when_exist_all\": \"when_exist_all failed\"}),\n\t})\n\n\terrors := v.Validate(context.TODO(), map[string]string{\n\t\t\"Username\": \"username\",\n\t\t\"Password\": \"password\",\n\t\t\"Data\":     \"\",\n\t})\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\nmap[data:[when_exist_all failed]]\nfalse\n```\n\n## Custom Validator\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n\t\"github.com/golodash/godash/slices\"\n)\n\ntype Person struct {\n\tUsername string `json:\"username\" g:\"required,min=3,max=32,duplicate_check\" duplicate_check:\"$field is duplicate\"`\n\tPassword string `json:\"password\" g:\"required,min=5,password\"`\n\tEmail    string `json:\"email\" g:\"required,email\"`\n}\n\nvar users = []string{\n\t\"ali\",\n\t\"james\",\n\t\"john\",\n}\n\nfunc duplicate_check(ctx context.Context, input interface{}) bool {\n\treturn slices.FindIndex(users, input) == -1\n}\n\nfunc main() {\n\tg := galidator.New().CustomValidators(galidator.Validators{\"duplicate_check\": duplicate_check})\n\tvalidator := g.Validator(Person{})\n\n\tuserInput := Person{\n\t\tUsername: \"ali\",\n\t\tPassword: \"123456789mH!\",\n\t\tEmail:    \"DoctorMK@gmail.com\",\n\t}\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\nmap[username:[username is duplicate]]\nfalse\n```\n\n## LenRange\n\nLenRange can be used in a struct tag like: `g:\"len_range=3\u00265\" len_range=\"len_range failed\"`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(g.R().LenRange(3, 5).SpecificMessages(galidator.Messages{\"len_range\": \"len_range failed\"}))\n\n\tuserInput := 3\n\n\terrors := validator.Validate(context.TODO(), userInput)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\nOutput:\n```\n[len_range failed]\nfalse\n```\n\n## Changing Default Error Messages\n\n1. Changing default error messages in generator layer:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\nfunc main() {\n\tg := galidator.New().CustomMessages(galidator.Messages{\n\t\t\"string\": \"$value is not string\",\n\t})\n\tvalidator := g.Validator(g.R().String())\n\n\terrors := validator.Validate(context.TODO(), 1)\n\n\tfmt.Println(errors)\n\tfmt.Println(errors == nil)\n}\n```\n\noutput:\n```\n[1 is not string]\n```\n\n2. Changing default error messages in validator layer (This layer overrides generator error messages-if same value that is defined in other layers gets defined in this layer too):\n\n```go\ng := galidator.New().CustomMessages(galidator.Messages{\n   \"string\": \"$value is not string\",\n})\nvalidator := g.Validator(g.R().String(), galidator.Messages{\n   \"string\": \"not\",\n})\n```\n\noutput:\n```\n[not]\n```\n\n3. Changing default error messages in ruleSet layer (This layer overrides generator and validator error messages-if same value that is defined in other layers gets defined in this layer too):\n\n```go\ng := galidator.New().CustomMessages(galidator.Messages{\n   \"string\": \"$value is not string\",\n})\nvalidator := g.Validator(g.R().String().SpecificMessages(galidator.Messages{\n\t\t\"string\": \"not valid\",\n\t}), galidator.Messages{\n\t\"string\": \"not\",\n})\n```\n\noutput:\n```\n[not valid]\n```\n\n## Defining `ruleSet` for Children of a Slice in Struct Tags\n\nIf you need to define a rule for children of a slice in struct tags, you should use\nsome proper prefix for those rules like: `c.` or `child.`\\\nAnd have in mind that with adding two or more of these prefixes, you keep digging in\ndeeper layers. like: `child.child.child.min` or `c.c.c.min` or `c.child.c.min` or... means go deep three slices and add `min` rule to children of the last slice.\n\nexample:\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"context\"\n\n\t\"github.com/golodash/galidator/v2\"\n)\n\ntype numbers struct {\n\tNumbers []int `g:\"c.min=1,c.max=5\" c.max:\"$value is not \u003c= $max\" c.min:\"$value is not \u003e= $min\"`\n}\n\nfunc main() {\n\tg := galidator.New()\n\tvalidator := g.Validator(numbers{})\n\n\tfmt.Println(validator.Validate(context.TODO(), numbers{\n\t\tNumbers: []int{\n\t\t\t1,\n\t\t\t0,\n\t\t\t5,\n\t\t\t35,\n\t\t},\n\t}))\n}\n```\n\noutput:\n```\nmap[Numbers:map[1:[0 is not \u003e= 1] 3:[35 is not \u003c= 5]]]\n```\n\n## Translator\n\nWhen calling `Validator.Validate` method with your data, you can pass a translator function to translate output of error messages to your desired language.\n\nFor example:\n\n```go\nvar (\n\tg = galidator.G()\n\tvalidator = g.Validator(g.R().Required())\n\ttranslates = map[string]string{\n    \t\"required\": \"this is required and it is translated\",\n\t}\n)\n\nfunc translator(input string) string {\n\tif out, ok := translates[input]; ok {\n\t\treturn out\n\t}\n\treturn input\n}\n\nfunc main() {\n\tfmt.Println(validator.Validate(context.TODO(), translator))\n}\n```\n\noutput:\n```go\n[this is required and it is translated]\n```\n\n# Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=golodash/galidator\u0026type=Date)](https://star-history.com/#golodash/galidator\u0026Date)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgolodash%2Fgalidator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgolodash%2Fgalidator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgolodash%2Fgalidator/lists"}