A flexible forms validation and rendering library for golang web development. Inspired by django-forms and wtforms.
Overview
- Validate HTTP request
- Rendering form-html
- Support parsing content-type "form-urlencoded", "json"
- Support many widgets for form field.
Getting Started
Install
go get github.com/bluele/gforms
Examples
See examples.
Usage
Define Form
userForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), gforms.NewFloatField( "weight", gforms.Validators{}, ), ))
Validate HTTP request
Server (code):
type User struct { Name string `gforms:"name"` Weight float32 `gforms:"weight"` } func main() { tplText := `<form method="post"> {{range $i, $field := .Fields}} <label>{{$field.GetName}}: </label>{{$field.Html}} {{range $ei, $err := $field.Errors}}<label class="error">{{$err}}</label>{{end}}<br /> {{end}}<input type="submit"> </form> ` tpl := template.Must(template.New("tpl").Parse(tplText)) userForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), gforms.NewFloatField( "weight", gforms.Validators{}, ), )) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") form := userForm(r) if r.Method != "POST" { tpl.Execute(w, form) return } if !form.IsValid() { tpl.Execute(w, form) return } user := User{} form.MapTo(&user) fmt.Fprintf(w, "ok: %v", user) }) http.ListenAndServe(":9000", nil) }
Client:
# show html form
$ curl -X GET localhost:9000/users
<form method="post">
<label>name: </label><input type="text" name="name" value=""></input>
<br />
<label>weight: </label><input type="text" name="weight" value=""></input>
<br />
<input type="submit">
</form>
# valid request
$ curl -X POST localhost:9000/users -d 'name=bluele&weight=71.9'
ok: {bluele 71.9}
# "name" field is required.
$ curl -X POST localhost:9000/users -d 'weight=71.9'
<form method="post">
<label>name: </label><input type="text" name="name" value=""></input>
<label class="error">This field is required.</label><br />
<label>weight: </label><input type="text" name="weight" value="71.9"></input>
<br />
<input type="submit">
</form>
Define Form by Struct Model
type User struct { Name string `gforms:"name"` Weight float32 `gforms:"weight"` } func initForm() { userForm := gforms.DefineModelForm(User{}, gforms.NewFields( // override User.name field gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), )) /* equal an above defined form. userForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), gforms.MaxLengthValidator(32), }, ), gforms.NewFloatField( "weight", gforms.Validators{}, ), )) */ }
Render HTML
FormInstance#Html
form := userForm(r) fmt.Println(form.Html()) /* # Output <input type="text" name="name"></input> <input type="text" name="weight"></input> */
FieldInstance#Html
form := userForm(r)
fmt.Println(form.GetField("name").Html())
/*
# Output
<input type="text" name="name"></input>
*/
Parse request data
(Default) Parse *http.Request to create a new FormInstance.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { form := userForm(r) ... }
Parse net/url.Values to create a new FormInstance.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // parse querystring values. form := userForm.FromUrlValues(r.URL.Query()) ... }
Customize Formfield attributes
customForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required(), }, gforms.TextInputWidget( map[string]string{ "class": "custom", }, )), )) form := customForm(r) fmt.Println(form.Html()) /* # Output <input type="text" name="name" value="" class="custom"></input> */
Custom Validation error message
userForm := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "name", gforms.Validators{ gforms.Required("Custom error required message."), gforms.MaxLengthValidator(32, "Custom error maxlength message."), }, ), ))
Support Fields
TextField
It maps value to FormInstance.CleanedData as type string.
gforms.NewTextField( "text", gforms.Validators{}, )
BooleanField
It maps value to FormInstance.CleanedData as type bool.
gforms.NewBooleanField( "checked", gforms.Validators{}, )
IntegerField
It maps value to FormInstance.CleanedData as type int.
gforms.NewIntegerField( "number", gforms.Validators{}, )
FloatField
It maps value to FormInstance.CleanedData as type float32 or float64.
gforms.NewFloatField( "floatNumber", gforms.Validators{}, )
MultipleTextField
It maps value to FormInstance.CleanedData as type []string.
gforms.NewMultipleTextField( "texts", gforms.Validators{}, )
DateTimeField
It maps value to FormInstance.CleanedData as type time.Time.
gforms.NewDateTimeField( "date", DefaultDateTimeFormat, gforms.Validators{}, )
Support Validators
Required validator
Added an error msg to FormInstance.Errors() if the field is not provided.
gforms.Validators{ gforms.Required(), },
Regexp validator
Added an error msg to FormInstance.Errors() if the regexp doesn't matched a value.
gforms.Validators{ gforms.RegexpValidator(`number-\d+`), },
Email validator
Added an error msg to FormInstance.Errors() if a value doesn't looks like an email address.
gforms.Validators{ gforms.EmailValidator(), },
URL Validator
Added an error msg to FormInstance.Errors() if a value doesn't looks like an url.
gforms.Validators{ gforms.URLValidator(), },
MinLength Validator
Added an error msg to FormInstance.Errors() if the length of value is less than specified first argument.
gforms.Validators{ gforms.MinLengthValidator(16), },
MaxLength Validator
Added an error msg to FormInstance.Errors() if the length of value is greater than specified first argument.
gforms.Validators{ gforms.MaxLengthValidator(256), },
MinValueValidator
Added an error msg to FormInstance.Errors() if value is less than specified first argument.
gforms.Validators{ gforms.MinValueValidator(16), },
MaxValueValidator
Added an error msg to FormInstance.Errors() if value is greater than specified first argument.
gforms.Validators{ gforms.MaxValueValidator(256), },
Support Widgets
SelectWidget
Form := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "gender", gforms.Validators{ gforms.Required(), }, gforms.SelectWidget( map[string]string{ "class": "custom", }, func() gforms.SelectOptions { return gforms.StringSelectOptions([][]string{ {"Men", "0"}, {"Women", "1"}, }) }, ), ), )) form = Form() fmt.Println(form.Html()) /* # output <select class="custom"> <option value="0">Men</option> <option value="1">Women</option> </select> */
RadioSelectWidget
Form := gforms.DefineForm(gforms.NewFields( gforms.NewTextField( "lang", gforms.Validators{ gforms.Required(), }, gforms.RadioSelectWidget( map[string]string{ "class": "custom", }, func() gforms.RadioOptions { return gforms.StringRadioOptions([][]string{ {"Golang", "0", "false", "false"}, {"Python", "1", "false", "true"}, }) }, ), ), )) form = Form() fmt.Println(form.Html()) /* # output <input type="radio" name="lang" value="0">Golang <input type="radio" name="lang" value="1" disabled>Python */
CheckboxMultipleWidget
Form := gforms.DefineForm(gforms.NewFields( gforms.NewMultipleTextField( "lang", gforms.Validators{ gforms.Required(), }, gforms.CheckboxMultipleWidget( map[string]string{ "class": "custom", }, func() gforms.CheckboxOptions { return gforms.StringCheckboxOptions([][]string{ {"Golang", "0", "false", "false"}, {"Python", "1", "false", "true"}, }) }, ), ), )) form := Form() fmt.Println(form.Html()) /* # output <input type="checkbox" name="lang" value="0">Golang <input type="checkbox" name="lang" value="1" disabled>Python */
TODO
- Support FileField, DateField, DateTimeField
- Writing more godoc and unit tests.
- Improve performance.
Author
Jun Kimura