{"id":20041285,"url":"https://github.com/gernest/gforms","last_synced_at":"2025-06-20T01:04:41.990Z","repository":{"id":57526424,"uuid":"39322336","full_name":"gernest/gforms","owner":"gernest","description":"forms library for golang","archived":false,"fork":false,"pushed_at":"2015-07-19T04:31:25.000Z","size":200,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-20T01:03:35.408Z","etag":null,"topics":[],"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/gernest.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-19T04:28:08.000Z","updated_at":"2023-04-01T13:34:23.000Z","dependencies_parsed_at":"2022-09-07T02:51:02.740Z","dependency_job_id":null,"html_url":"https://github.com/gernest/gforms","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/gernest/gforms","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gernest%2Fgforms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gernest%2Fgforms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gernest%2Fgforms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gernest%2Fgforms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gernest","download_url":"https://codeload.github.com/gernest/gforms/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gernest%2Fgforms/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260857363,"owners_count":23073435,"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":[],"created_at":"2024-11-13T10:46:06.141Z","updated_at":"2025-06-20T01:04:36.942Z","avatar_url":"https://github.com/gernest.png","language":"Go","readme":"# GForms\nA flexible forms validation and rendering library for golang web development. \nInspired by [django-forms](https://docs.djangoproject.com/en/dev/topics/forms/) and [wtforms](https://github.com/wtforms/wtforms).\n\n[![wercker status](https://app.wercker.com/status/51a7f6720baf8e67a28241790380d19b/s \"wercker status\")](https://app.wercker.com/project/bykey/51a7f6720baf8e67a28241790380d19b)\n\n## Overview\n\n* Validate HTTP request\n* Rendering form-html\n* Support parsing content-type \"form-urlencoded\", \"json\"\n* Support many widgets for form field.\n\n# Getting Started\n\n## Install\n\n```\ngo get github.com/bluele/gforms\n```\n\n## Examples\n\nSee [examples](https://github.com/bluele/gforms/tree/master/examples).\n\n## Usage\n\n### Define Form\n\n```go\nuserForm := gforms.DefineForm(gforms.NewFields(\n  gforms.NewTextField(\n    \"name\",\n    gforms.Validators{\n      gforms.Required(),\n      gforms.MaxLengthValidator(32),\n    },\n  ),\n  gforms.NewFloatField(\n    \"weight\",\n    gforms.Validators{},\n  ),\n))\n```\n\n### Validate HTTP request\n\nServer ([code](https://github.com/bluele/gforms/blob/master/examples/simple_form.go)):\n\n```go\ntype User struct {\n  Name   string  `gforms:\"name\"`\n  Weight float32 `gforms:\"weight\"`\n}\n\nfunc main() {\n  tplText := `\u003cform method=\"post\"\u003e\n{{range $i, $field := .Fields}}\n  \u003clabel\u003e{{$field.GetName}}: \u003c/label\u003e{{$field.Html}}\n  {{range $ei, $err := $field.Errors}}\u003clabel class=\"error\"\u003e{{$err}}\u003c/label\u003e{{end}}\u003cbr /\u003e\n{{end}}\u003cinput type=\"submit\"\u003e\n\u003c/form\u003e\n  `\n  tpl := template.Must(template.New(\"tpl\").Parse(tplText))\n\n  userForm := gforms.DefineForm(gforms.NewFields(\n    gforms.NewTextField(\n      \"name\",\n      gforms.Validators{\n        gforms.Required(),\n        gforms.MaxLengthValidator(32),\n      },\n    ),\n    gforms.NewFloatField(\n      \"weight\",\n      gforms.Validators{},\n    ),\n  ))\n\n  http.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n    w.Header().Set(\"Content-Type\", \"text/html\")\n    form := userForm(r)\n    if r.Method != \"POST\" {\n      tpl.Execute(w, form)\n      return\n    }\n    if !form.IsValid() {\n      tpl.Execute(w, form)\n      return\n    }\n    user := User{}\n    form.MapTo(\u0026user)\n    fmt.Fprintf(w, \"ok: %v\", user)\n  })\n  http.ListenAndServe(\":9000\", nil)\n}\n```\n\nClient:\n\n```\n# show html form\n$ curl -X GET localhost:9000/users\n\u003cform method=\"post\"\u003e\n  \u003clabel\u003ename: \u003c/label\u003e\u003cinput type=\"text\" name=\"name\" value=\"\"\u003e\u003c/input\u003e\n  \u003cbr /\u003e\n\n  \u003clabel\u003eweight: \u003c/label\u003e\u003cinput type=\"text\" name=\"weight\" value=\"\"\u003e\u003c/input\u003e\n  \u003cbr /\u003e\n\u003cinput type=\"submit\"\u003e\n\u003c/form\u003e\n\n# valid request\n$ curl -X POST localhost:9000/users -d 'name=bluele\u0026weight=71.9'\nok: {bluele 71.9}\n\n# \"name\" field is required.\n$ curl -X POST localhost:9000/users -d 'weight=71.9'\n\u003cform method=\"post\"\u003e\n  \u003clabel\u003ename: \u003c/label\u003e\u003cinput type=\"text\" name=\"name\" value=\"\"\u003e\u003c/input\u003e\n  \u003clabel class=\"error\"\u003eThis field is required.\u003c/label\u003e\u003cbr /\u003e\n\n  \u003clabel\u003eweight: \u003c/label\u003e\u003cinput type=\"text\" name=\"weight\" value=\"71.9\"\u003e\u003c/input\u003e\n  \u003cbr /\u003e\n\u003cinput type=\"submit\"\u003e\n\u003c/form\u003e\n```\n\n### Define Form by Struct Model\n\n```go\ntype User struct {\n  Name   string  `gforms:\"name\"`\n  Weight float32 `gforms:\"weight\"`\n}\n\nfunc initForm() {\n  userForm := gforms.DefineModelForm(User{}, gforms.NewFields(\n    // override User.name field\n    gforms.NewTextField(\n      \"name\",\n      gforms.Validators{\n        gforms.Required(),\n        gforms.MaxLengthValidator(32),\n      },\n    ),\n  ))\n  /* equal an above defined form.\n  userForm := gforms.DefineForm(gforms.NewFields(\n    gforms.NewTextField(\n      \"name\",\n      gforms.Validators{\n        gforms.Required(),\n        gforms.MaxLengthValidator(32),\n      },\n    ),\n    gforms.NewFloatField(\n      \"weight\",\n      gforms.Validators{},\n    ),\n  ))\n  */\n}\n```\n\n## Render HTML\n\n### FormInstance#Html\n\n```go\nform := userForm(r)\nfmt.Println(form.Html())\n/* \n# Output\n\u003cinput type=\"text\" name=\"name\"\u003e\u003c/input\u003e\n\u003cinput type=\"text\" name=\"weight\"\u003e\u003c/input\u003e\n*/\n```\n\n### FieldInstance#Html\n\n```\nform := userForm(r)\nfmt.Println(form.GetField(\"name\").Html())\n/* \n# Output\n\u003cinput type=\"text\" name=\"name\"\u003e\u003c/input\u003e\n*/\n```\n\n## Parse request data\n\n### (Default) Parse `*http.Request` to create a new `FormInstance`.\n\n```go\nhttp.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n  form := userForm(r)  \n  ...\n}\n```\n\n### Parse `net/url.Values` to create a new `FormInstance`.\n\n```go\nhttp.HandleFunc(\"/\", func(w http.ResponseWriter, r *http.Request) {\n  // parse querystring values.\n  form := userForm.FromUrlValues(r.URL.Query())\n  ...\n}\n```\n\n## Customize Formfield attributes\n\n```go\ncustomForm := gforms.DefineForm(gforms.NewFields(\n  gforms.NewTextField(\n    \"name\",\n    gforms.Validators{\n      gforms.Required(),\n    },\n    gforms.TextInputWidget(\n      map[string]string{\n        \"class\": \"custom\",\n      },\n    )),\n))\n\nform := customForm(r)\nfmt.Println(form.Html())\n/* \n# Output\n\u003cinput type=\"text\" name=\"name\" value=\"\" class=\"custom\"\u003e\u003c/input\u003e\n*/\n```\n\n## Custom Validation error message\n\n```go\nuserForm := gforms.DefineForm(gforms.NewFields(\n  gforms.NewTextField(\n    \"name\",\n    gforms.Validators{\n      gforms.Required(\"Custom error required message.\"),\n      gforms.MaxLengthValidator(32, \"Custom error maxlength message.\"),\n    },\n  ),\n))\n```\n\n## Support Fields\n\n### TextField\n\nIt maps value to FormInstance.CleanedData as type `string`.\n\n```go\ngforms.NewTextField(\n  \"text\",\n  gforms.Validators{},\n)\n```\n\n### BooleanField\n\nIt maps value to FormInstance.CleanedData as type `bool`.\n\n```go\ngforms.NewBooleanField(\n  \"checked\",\n  gforms.Validators{},\n)\n```\n\n### IntegerField\n\nIt maps value to FormInstance.CleanedData as type `int`.\n\n```go\ngforms.NewIntegerField(\n  \"number\",\n  gforms.Validators{},\n)\n```\n\n### FloatField\n\nIt maps value to FormInstance.CleanedData as type `float32` or `float64`.\n\n```go\ngforms.NewFloatField(\n  \"floatNumber\",\n  gforms.Validators{},\n)\n```\n\n### MultipleTextField\n\nIt maps value to FormInstance.CleanedData as type `[]string`.\n\n```go\ngforms.NewMultipleTextField(\n  \"texts\",\n  gforms.Validators{},\n)\n```\n\n### DateTimeField\n\nIt maps value to FormInstance.CleanedData as type `time.Time`.\n\n```go\ngforms.NewDateTimeField(\n  \"date\", \n  DefaultDateTimeFormat, \n  gforms.Validators{},  \n)\n```\n\n## Support Validators\n\n### Required validator\n\nAdded an error msg to FormInstance.Errors() if the field is not provided.\n\n```go\ngforms.Validators{\n  gforms.Required(),\n},\n```\n\n### Regexp validator\n\nAdded an error msg to FormInstance.Errors() if the regexp doesn't matched a value.\n\n```go\ngforms.Validators{\n  gforms.RegexpValidator(`number-\\d+`),\n},\n```\n\n### Email validator\n\nAdded an error msg to FormInstance.Errors() if a value doesn't looks like an email address.\n\n```go\ngforms.Validators{\n  gforms.EmailValidator(),\n},\n```\n\n### URL Validator\n\nAdded an error msg to FormInstance.Errors() if a value doesn't looks like an url.\n\n```go\ngforms.Validators{\n  gforms.URLValidator(),\n},\n```\n\n### MinLength Validator\n\nAdded an error msg to FormInstance.Errors() if the length of value is less than specified first argument.\n\n```go\ngforms.Validators{\n  gforms.MinLengthValidator(16),\n},\n```\n\n### MaxLength Validator\n\nAdded an error msg to FormInstance.Errors() if the length of value is greater than specified first argument.\n\n```go\ngforms.Validators{\n  gforms.MaxLengthValidator(256),\n},\n```\n\n### MinValueValidator\n\nAdded an error msg to FormInstance.Errors() if value is less than specified first argument.\n\n```go\ngforms.Validators{\n  gforms.MinValueValidator(16),\n},\n```\n\n### MaxValueValidator\n\nAdded an error msg to FormInstance.Errors() if value is greater than specified first argument.\n\n```go\ngforms.Validators{\n  gforms.MaxValueValidator(256),\n},\n```\n\n## Support Widgets\n\n### SelectWidget\n\n```go\nForm := gforms.DefineForm(gforms.NewFields(\n  gforms.NewTextField(\n    \"gender\",\n    gforms.Validators{\n      gforms.Required(),\n    },\n    gforms.SelectWidget(\n      map[string]string{\n        \"class\": \"custom\",\n      },\n      func() gforms.SelectOptions {\n        return gforms.StringSelectOptions([][]string{\n          {\"Men\", \"0\"},\n          {\"Women\", \"1\"},\n        })\n      },\n    ),\n  ),\n))\n\nform = Form()\nfmt.Println(form.Html())\n/*\n# output\n\u003cselect class=\"custom\"\u003e\n\u003coption value=\"0\"\u003eMen\u003c/option\u003e\n\u003coption value=\"1\"\u003eWomen\u003c/option\u003e\n\u003c/select\u003e\n*/\n```\n\n### RadioSelectWidget\n\n```go\nForm := gforms.DefineForm(gforms.NewFields(\n    gforms.NewTextField(\n      \"lang\",\n      gforms.Validators{\n        gforms.Required(),\n      },\n      gforms.RadioSelectWidget(\n        map[string]string{\n          \"class\": \"custom\",\n        },\n        func() gforms.RadioOptions {\n          return gforms.StringRadioOptions([][]string{\n            {\"Golang\", \"0\", \"false\", \"false\"},\n            {\"Python\", \"1\", \"false\", \"true\"},\n          })\n        },\n      ),\n    ),  \n))\n\nform = Form()\nfmt.Println(form.Html())\n/*\n# output\n\u003cinput type=\"radio\" name=\"lang\" value=\"0\"\u003eGolang\n\u003cinput type=\"radio\" name=\"lang\" value=\"1\" disabled\u003ePython\n*/\n```\n\n### CheckboxMultipleWidget\n\n```go\nForm := gforms.DefineForm(gforms.NewFields(\n    gforms.NewMultipleTextField(\n      \"lang\",\n      gforms.Validators{\n        gforms.Required(),\n      },\n      gforms.CheckboxMultipleWidget(\n        map[string]string{\n          \"class\": \"custom\",\n        },\n        func() gforms.CheckboxOptions {\n          return gforms.StringCheckboxOptions([][]string{\n            {\"Golang\", \"0\", \"false\", \"false\"},\n            {\"Python\", \"1\", \"false\", \"true\"},\n          })\n        },\n      ),\n    ),\n))\n\nform := Form()\nfmt.Println(form.Html())\n/*\n# output\n\u003cinput type=\"checkbox\" name=\"lang\" value=\"0\"\u003eGolang\n\u003cinput type=\"checkbox\" name=\"lang\" value=\"1\" disabled\u003ePython\n*/\n```\n\n# TODO\n\n* Support FileField, DateField, DateTimeField\n* Writing more godoc and unit tests.\n* Improve performance.\n\n# Author\n\n**Jun Kimura**\n\n* \u003chttp://github.com/bluele\u003e\n* \u003cjunkxdev@gmail.com\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgernest%2Fgforms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgernest%2Fgforms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgernest%2Fgforms/lists"}