A flexible forms validation and rendering library for golang web development. Inspired by django-forms and wtforms.
- Validate HTTP request
- Rendering form-html
- Support parsing content-type "form-urlencoded", "json"
- Support many widgets for form field.
go get github.com/bluele/gforms
See examples.
userForm := gforms.DefineForm(gforms.NewFields(
gforms.NewTextField(
"name",
gforms.Validators{
gforms.Required(),
gforms.MaxLengthValidator(32),
},
),
gforms.NewFloatField(
"weight",
gforms.Validators{},
),
))
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>
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{},
),
))
*/
}
form := userForm(r)
fmt.Println(form.Html())
/*
# Output
<input type="text" name="name"></input>
<input type="text" name="weight"></input>
*/
form := userForm(r)
fmt.Println(form.GetField("name").Html())
/*
# Output
<input type="text" name="name"></input>
*/
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
form := userForm(r)
...
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// parse querystring values.
form := userForm.FromUrlValues(r.URL.Query())
...
}
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>
*/
userForm := gforms.DefineForm(gforms.NewFields(
gforms.NewTextField(
"name",
gforms.Validators{
gforms.Required("Custom error required message."),
gforms.MaxLengthValidator(32, "Custom error maxlength message."),
},
),
))
It maps value to FormInstance.CleanedData as type string
.
gforms.NewTextField(
"text",
gforms.Validators{},
)
It maps value to FormInstance.CleanedData as type bool
.
gforms.NewBooleanField(
"checked",
gforms.Validators{},
)
It maps value to FormInstance.CleanedData as type int
.
gforms.NewIntegerField(
"number",
gforms.Validators{},
)
It maps value to FormInstance.CleanedData as type float32
or float64
.
gforms.NewFloatField(
"floatNumber",
gforms.Validators{},
)
It maps value to FormInstance.CleanedData as type []string
.
gforms.NewMultipleTextField(
"texts",
gforms.Validators{},
)
It maps value to FormInstance.CleanedData as type time.Time
.
gforms.NewDateTimeField(
"date",
DefaultDateTimeFormat,
gforms.Validators{},
)
Added an error msg to FormInstance.Errors() if the field is not provided.
gforms.Validators{
gforms.Required(),
},
Added an error msg to FormInstance.Errors() if the regexp doesn't matched a value.
gforms.Validators{
gforms.RegexpValidator(`number-\d+`),
},
Added an error msg to FormInstance.Errors() if a value doesn't looks like an email address.
gforms.Validators{
gforms.EmailValidator(),
},
Added an error msg to FormInstance.Errors() if a value doesn't looks like an url.
gforms.Validators{
gforms.URLValidator(),
},
Added an error msg to FormInstance.Errors() if the length of value is less than specified first argument.
gforms.Validators{
gforms.MinLengthValidator(16),
},
Added an error msg to FormInstance.Errors() if the length of value is greater than specified first argument.
gforms.Validators{
gforms.MaxLengthValidator(256),
},
Added an error msg to FormInstance.Errors() if value is less than specified first argument.
gforms.Validators{
gforms.MinValueValidator(16),
},
Added an error msg to FormInstance.Errors() if value is greater than specified first argument.
gforms.Validators{
gforms.MaxValueValidator(256),
},
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>
*/
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
*/
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
*/
- Support FileField, DateField, DateTimeField
- Writing more godoc and unit tests.
- Improve performance.
Jun Kimura