Documentation ¶
Overview ¶
Package forms provides tools for validating data found in gadget.Request.Params. Its structure is inspired by Django's forms library and is intended to be both declarative and highly independent of your application's model layer. Forms are struct types that embed *DefaultForm and declare as their fields pointers to any number of Field types. They look something like this:
type InvoiceForm struct { *DefaultForm Client, Notes *StringField Date *TimeField Number *IntField }
Index ¶
- func Copy(f Form, target interface{}) error
- func Init(form Form, initializer func(Form))
- func IsValid(f Form) bool
- func Populate(form Form, payload map[string]interface{}) error
- type BaseField
- type BoolField
- type DefaultForm
- type Float64Field
- type Form
- type FormField
- type IntField
- type IntSliceField
- type StringField
- type TimeField
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Copy ¶
Copy transfers data from a validated Form to another struct for further processing (presumably persistance). The target struct must have a field of the appropriate type and the same name for every FormField in the Form.
Copy will return an error if the Form has not passed validation, if it cannot find a corresponding field on the target struct for a FormField, or if it cannot set the FormField's value on the target field.
Example ¶
package main import ( "fmt" "github.com/redneckbeard/gadget/forms" ) func main() { type Invoice struct { Client, Notes string Paid bool Number int } type InvoiceForm struct { *forms.DefaultForm Client, Notes *forms.StringField Paid *forms.BoolField Number *forms.IntField } form := &InvoiceForm{} forms.Init(form, nil) forms.Populate(form, map[string]interface{}{ "Client": "M.A.D.", "Notes": "Some day, Gadget, some day...", "Paid": "1", "Number": 23, }) fmt.Println(forms.IsValid(form)) invoice := &Invoice{} forms.Copy(form, invoice) fmt.Println(invoice.Client) fmt.Println(invoice.Notes) fmt.Println(invoice.Paid) fmt.Println(invoice.Number) }
Output: true M.A.D. Some day, Gadget, some day... true 23
func Init ¶
Init correctly initializes all FormFields and the embedded DefaultForm on a struct. Its first argument a Form, and its second an optional func that will receive the form as its only argument after initialization is complete. This callback enables you to do additional setup on FormFields included in your Form.
Example ¶
package main import ( "fmt" "github.com/redneckbeard/gadget/forms" ) func main() { type ArticleForm struct { *forms.DefaultForm Title, Body *forms.StringField AuthorId *forms.IntField } form := &ArticleForm{} forms.Init(form, func(f forms.Form) { form := f.(*ArticleForm) form.AuthorId.Required = false }) forms.Populate(form, map[string]interface{}{ "Title": "Mission: Stop Dr. Claw", }) fmt.Println(forms.IsValid(form)) fmt.Println(form.AuthorId.Error()) fmt.Println(form.Body.Error()) }
Output: false <nil> This field is required
func IsValid ¶
IsValid calls the Clean method on all of a Form's FormFields. As a result, if IsValid returns true, the Value fields of all required FormFields will be non-nil. If false, error messages may be retrieved by the Error method of an individual field or by retrieving the error for a field by name from the Form's Errors map.
If validation is needed beyond what a FormField type provides by default, Forms may define special methods to perform more robust checks on the value of the Data field. These methods are named "Clean<Fieldname>" and receive the field being validated as their argument. An example is provided below.
Example ¶
package main import ( "fmt" "github.com/redneckbeard/gadget/forms" "regexp" ) type UserForm struct { *forms.DefaultForm Username, Email *forms.StringField } func (form *UserForm) CleanEmail(f forms.FormField) { field := f.(*forms.StringField) naiveEmailPattern := regexp.MustCompile(`[\w.-]+@[\w.-]\.(com|net|org)`) if !naiveEmailPattern.MatchString(field.Value) { field.SetError("Email must be an email") } } func main() { /* *type UserForm struct { * *forms.DefaultForm * Username, Email *forms.StringField *} * *func (form *UserForm) CleanEmail(f forms.FormField) { * field := f.(*forms.StringField) * naiveEmailPattern := regexp.MustCompile(`[\w.-]+@[\w.-]\.(com|net|org)`) * if !naiveEmailPattern.MatchString(field.Value) { * field.SetError("Email must be an email") * } *} */ form := &UserForm{} forms.Init(form, nil) forms.Populate(form, map[string]interface{}{ "Username": "penny", "Email": "clearly not an email address", }) fmt.Println(forms.IsValid(form)) fmt.Println(form.Email.Error()) }
Output: false Email must be an email
func Populate ¶
Populate copies data from a map[string]interface{} value into the Data members of the corresponding FormFields of the Form. The keys of the map must be a case-sensitive exact match of exported names of FormFields on the struct. Populate will return an error if Init has not yet been called on the Form.
Note that the type of the second argument is not map[string][]string. This is meant to provide ease of use with gadget.Request.Params over http.Request.Form.
Types ¶
type BaseField ¶
type BaseField struct { Data interface{} Messages map[string]string Required bool Placeholder bool // contains filtered or unexported fields }
func (*BaseField) DefaultMessages ¶
func (field *BaseField) DefaultMessages()
func (*BaseField) GetMessage ¶
func (*BaseField) SetMessage ¶
type BoolField ¶
func (*BoolField) Clean ¶
func (field *BoolField) Clean()
Boolfield validates the presence of a boolean value. If the Data on the FormField is an int, 0 is taken for false and 1 for true. If it is a string, it is parsed by strconv.ParseBool.
func (*BoolField) DefaultMessages ¶
func (field *BoolField) DefaultMessages()
type DefaultForm ¶
DefaultForm provides a complete implementation of the Form interface for you to embed in your form struct.
func (*DefaultForm) HasErrors ¶
func (f *DefaultForm) HasErrors() bool
HasErrors returns true if the Error method of any of a Form's FormField members returns non-nil.
type Float64Field ¶
Float64Field validates the presence of a float64 value. If the Data on the FormField is a string, the Clean method will attempt to parse it. If it is an int, it will cast it to a float64.
func (*Float64Field) Clean ¶
func (field *Float64Field) Clean()
func (*Float64Field) Copy ¶
func (field *Float64Field) Copy(v reflect.Value)
func (*Float64Field) DefaultMessages ¶
func (field *Float64Field) DefaultMessages()
type Form ¶
type Form interface { HasErrors() bool // contains filtered or unexported methods }
Form is the interface that wraps the validation functionality provided by this package. To implement the Form interface, struct types must embed a pointer to DefaultForm, since the interface includes unexported fields that DefaultForm provides. DefaultForm implements all the methods necessary to satisfy the interface.
type FormField ¶
type FormField interface { Clean() Copy(reflect.Value) DefaultMessages() Error() error GetMessage(string) string Set(interface{}) SetError(string) SetMessage(string, string) // contains filtered or unexported methods }
FormField is the interface that encapsulates field-level form operations. All types implementing FormField should be struct types that embed BaseField, which provides all methods except Clean and Copy. Individual field types must implement those methods appropriatly for the types of data they are intended to validate.
By virtue of their embedded BaseField, all FormFields have a Data field of type interface{}. The FormFields themselves conventionally have a Value field of the type that they purport to validate. All FormFields are required unless their Required field is set to false in the form's SetOptions method.
The forms package ships with FormField types for string, int, bool, float64, and time.Time values. Users can easily define additional fields. Refer to the source for the builtin FormField types for details of how to define new ones.
type IntField ¶
IntField validates the presence of an int value. If the Data on the FormField is string, its Clean method will attempt to parse it.
func (*IntField) DefaultMessages ¶
func (field *IntField) DefaultMessages()
type IntSliceField ¶
func (*IntSliceField) Clean ¶
func (field *IntSliceField) Clean()
func (*IntSliceField) Copy ¶
func (field *IntSliceField) Copy(v reflect.Value)
func (*IntSliceField) DefaultMessages ¶
func (field *IntSliceField) DefaultMessages()
type StringField ¶
StringField validates the presences of a string value.
func (*StringField) Clean ¶
func (field *StringField) Clean()
func (*StringField) Copy ¶
func (field *StringField) Copy(v reflect.Value)
func (*StringField) DefaultMessages ¶
func (field *StringField) DefaultMessages()
type TimeField ¶
TimeField validates the presence of a Time value. If the value is an int64, it is parsed as seconds since the epoch. If it is a string, TimeField will attempt to parse it with the value of its Format field as the layout. The default time format is RFC 33339.
func (*TimeField) DefaultMessages ¶
func (field *TimeField) DefaultMessages()