 Documentation
      ¶
      Documentation
      ¶
    
    
  
    
  
    Overview ¶
Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values.
It has the following features:
- Primitives types cause zero allocations.
- Supports map of almost all types.
- Supports both Numbered and Normal arrays eg. "Array[0]" and just "Array" with multiple values passed.
- Array honours the specified index. eg. if "Array[2]" is the only Array value passed down, it will be put at index 2; if array isn't big enough it will be expanded.
- Only creates objects as necessary eg. if no `array` or `map` values are passed down, the `array` and `map` are left as their default values in the struct.
- Allows for Custom Type registration.
- Handles time.Time using RFC3339 time format by default, but can easily be changed by registering a Custom Type, see below.
- Handles Encoding & Decoding of almost all Go types eg. can Decode into struct, array, map, int... and Encode a struct, array, map, int...
Common Questions ¶
Questions
Does it support encoding.TextUnmarshaler? No because TextUnmarshaler only accepts []byte but posted values can have multiple values, so is not suitable.
Supported Types ¶
out of the box supported types
- string 
- bool 
- int, int8, int16, int32, int64 
- uint, uint8, uint16, uint32, uint64 
- float32, float64 
- struct and anonymous struct 
- interface{} 
- time.Time` - by default using RFC3339 
- a `pointer` to one of the above types 
- slice, array 
- map 
- `custom types` can override any of the above types 
- many other types may be supported inherently (eg. bson.ObjectId is type ObjectId string, which will get populated by the string type - **NOTE**: map, struct and slice nesting are ad infinitum. 
Usage ¶
symbols
- Use symbol `.` for separating fields/structs. (eg. `structfield.field`)
- Use `[index or key]` for access to index of a slice/array or key for map. (eg. `arrayfield[0]`, `mapfield[keyvalue]`)
html
<form method="POST">
    <input type="text" name="Name" value="joeybloggs"/>
    <input type="text" name="Age" value="3"/>
    <input type="text" name="Gender" value="Male"/>
    <input type="text" name="Address[0].Name" value="26 Here Blvd."/>
    <input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
    <input type="text" name="Address[1].Name" value="26 There Blvd."/>
    <input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
    <input type="text" name="active" value="true"/>
    <input type="text" name="MapExample[key]" value="value"/>
    <input type="text" name="NestedMap[key][key]" value="value"/>
    <input type="text" name="NestedArray[0][0]" value="value"/>
    <input type="submit"/>
</form>
Example ¶
example decoding the above HTML
package main
import (
    "fmt"
    "log"
    "net/url"
    "github.com/go-playground/form"
)
// Address contains address information
type Address struct {
    Name  string
    Phone string
}
// User contains user information
type User struct {
    Name        string
    Age         uint8
    Gender      string
    Address     []Address
    Active      bool `form:"active"`
    MapExample  map[string]string
    NestedMap   map[string]map[string]string
    NestedArray [][]string
}
// use a single instance of Decoder, it caches struct info
var decoder *form.Decoder
func main() {
    decoder = form.NewDecoder()
    // this simulates the results of http.Request's ParseForm() function
    values := parseForm()
    var user User
    // must pass a pointer
    err := decoder.Decode(&user, values)
    if err != nil {
        log.Panic(err)
    }
    fmt.Printf("%#v\n", user)
}
// this simulates the results of http.Request's ParseForm() function
func parseForm() url.Values {
    return url.Values{
        "Name":                []string{"joeybloggs"},
        "Age":                 []string{"3"},
        "Gender":              []string{"Male"},
        "Address[0].Name":     []string{"26 Here Blvd."},
        "Address[0].Phone":    []string{"9(999)999-9999"},
        "Address[1].Name":     []string{"26 There Blvd."},
        "Address[1].Phone":    []string{"1(111)111-1111"},
        "active":              []string{"true"},
        "MapExample[key]":     []string{"value"},
        "NestedMap[key][key]": []string{"value"},
        "NestedArray[0][0]":   []string{"value"},
    }
}
example encoding
package main
import (
    "fmt"
    "log"
    "github.com/go-playground/form"
)
// Address contains address information
type Address struct {
    Name  string
    Phone string
}
// User contains user information
type User struct {
    Name        string
    Age         uint8
    Gender      string
    Address     []Address
    Active      bool `form:"active"`
    MapExample  map[string]string
    NestedMap   map[string]map[string]string
    NestedArray [][]string
}
// use a single instance of Encoder, it caches struct info
var encoder *form.Encoder
func main() {
    encoder = form.NewEncoder()
    user := User{
        Name:   "joeybloggs",
        Age:    3,
        Gender: "Male",
        Address: []Address{
            {Name: "26 Here Blvd.", Phone: "9(999)999-9999"},
            {Name: "26 There Blvd.", Phone: "1(111)111-1111"},
        },
        Active:      true,
        MapExample:  map[string]string{"key": "value"},
        NestedMap:   map[string]map[string]string{"key": {"key": "value"}},
        NestedArray: [][]string{{"value"}},
    }
    // must pass a pointer
    values, err := encoder.Encode(&user)
    if err != nil {
        log.Panic(err)
    }
    fmt.Printf("%#v\n", values)
}
Registering Custom Types ¶
Decoder
decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
        return time.Parse("2006-01-02", vals[0])
    }, time.Time{})
ADDITIONAL: if a struct type is registered, the function will only be called
if a url.Value exists for the struct and not just the struct fields
eg. url.Values{"User":"Name%3Djoeybloggs"} will call the custom type function
with 'User' as the type, however url.Values{"User.Name":"joeybloggs"} will not.
Encoder
encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {
        return []string{x.(time.Time).Format("2006-01-02")}, nil
    }, time.Time{})
Ignoring Fields ¶
you can tell form to ignore fields using `-` in the tag
type MyStruct struct {
    Field string `form:"-"`
}
Omitempty ¶
you can tell form to omit empty fields using `,omitempty` or `FieldName,omitempty` in the tag
type MyStruct struct {
    Field  string `form:",omitempty"`
    Field2 string `form:"CustomFieldName,omitempty"`
}
Notes ¶
To maximize compatibility with other systems the Encoder attempts to avoid using array indexes in url.Values if at all possible.
eg.
// A struct field of
Field []string{"1", "2", "3"}
// will be output a url.Value as
"Field": []string{"1", "2", "3"}
and not
"Field[0]": []string{"1"}
"Field[1]": []string{"2"}
"Field[2]": []string{"3"}
// however there are times where it is unavoidable, like with pointers
i := int(1)
Field []*string{nil, nil, &i}
// to avoid index 1 and 2 must use index
"Field[2]": []string{"1"}
Index ¶
- func ExtractType(current reflect.Value) (reflect.Value, reflect.Kind)
- type AnonymousMode
- type DecodeCustomTypeFunc
- type DecodeErrors
- type Decoder
- func (d *Decoder) Decode(v interface{}, values url.Values) (err error)
- func (d *Decoder) RegisterCustomTypeFunc(fn DecodeCustomTypeFunc, types ...interface{})
- func (d *Decoder) RegisterTagNameFunc(fn TagNameFunc)
- func (d *Decoder) SetMaxArraySize(size uint)
- func (d *Decoder) SetMode(mode Mode)
- func (d *Decoder) SetTagName(tagName string)
 
- type EncodeCustomTypeFunc
- type EncodeErrors
- type Encoder
- func (e *Encoder) Encode(v interface{}) (values url.Values, err error)
- func (e *Encoder) RegisterCustomTypeFunc(fn EncodeCustomTypeFunc, types ...interface{})
- func (e *Encoder) RegisterTagNameFunc(fn TagNameFunc)
- func (e *Encoder) SetAnonymousMode(mode AnonymousMode)
- func (e *Encoder) SetMode(mode Mode)
- func (e *Encoder) SetTagName(tagName string)
 
- type InvalidDecoderError
- type InvalidEncodeError
- type Mode
- type TagNameFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type AnonymousMode ¶
type AnonymousMode uint8
AnonymousMode specifies how data should be rolled up or separated from anonymous structs
const ( // AnonymousEmbed embeds anonymous data when encoding // eg. type A struct { Field string } // type B struct { A, Field string } // encode results: url.Values{"Field":[]string{"B FieldVal", "A FieldVal"}} AnonymousEmbed AnonymousMode = iota // AnonymousSeparate does not embed anonymous data when encoding // eg. type A struct { Field string } // type B struct { A, Field string } // encode results: url.Values{"Field":[]string{"B FieldVal"}, "A.Field":[]string{"A FieldVal"}} AnonymousSeparate )
type DecodeCustomTypeFunc ¶ added in v1.3.0
DecodeCustomTypeFunc allows for registering/overriding types to be parsed.
type DecodeErrors ¶
DecodeErrors is a map of errors encountered during form decoding
func (DecodeErrors) Error ¶
func (d DecodeErrors) Error() string
type Decoder ¶
type Decoder struct {
	// contains filtered or unexported fields
}
    Decoder is the main decode instance
func NewDecoder ¶
func NewDecoder() *Decoder
NewDecoder creates a new decoder instance with sane defaults
func (*Decoder) Decode ¶
Decode parses the given values and sets the corresponding struct and/or type values
Decode returns an InvalidDecoderError if interface passed is invalid.
func (*Decoder) RegisterCustomTypeFunc ¶
func (d *Decoder) RegisterCustomTypeFunc(fn DecodeCustomTypeFunc, types ...interface{})
RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types. NOTE: This method is not thread-safe it is intended that these all be registered prior to any parsing
ADDITIONAL: if a struct type is registered, the function will only be called if a url.Value exists for the struct and not just the struct fields eg. url.Values{"User":"Name%3Djoeybloggs"} will call the custom type function with `User` as the type, however url.Values{"User.Name":"joeybloggs"} will not.
func (*Decoder) RegisterTagNameFunc ¶
func (d *Decoder) RegisterTagNameFunc(fn TagNameFunc)
RegisterTagNameFunc registers a custom tag name parser function NOTE: This method is not thread-safe it is intended that these all be registered prior to any parsing
ADDITIONAL: once a custom function has been registered the default, or custom set, tag name is ignored and relies 100% on the function for the name data. The return value WILL BE CACHED and so return value must be consistent.
func (*Decoder) SetMaxArraySize ¶ added in v1.5.0
SetMaxArraySize sets maximum array size that can be created. This limit is for the array indexing this library supports to avoid potential DOS or man-in-the-middle attacks using an unusually high number. DEFAULT: 10000
func (*Decoder) SetTagName ¶
SetTagName sets the given tag name to be used by the decoder. Default is "form"
type EncodeCustomTypeFunc ¶ added in v1.4.0
EncodeCustomTypeFunc allows for registering/overriding types to be parsed.
type EncodeErrors ¶ added in v1.4.0
EncodeErrors is a map of errors encountered during form encoding
func (EncodeErrors) Error ¶ added in v1.4.0
func (e EncodeErrors) Error() string
type Encoder ¶ added in v1.4.0
type Encoder struct {
	// contains filtered or unexported fields
}
    Encoder is the main encode instance
func NewEncoder ¶ added in v1.4.0
func NewEncoder() *Encoder
NewEncoder creates a new encoder instance with sane defaults
func (*Encoder) Encode ¶ added in v1.4.0
Encode encodes the given values and sets the corresponding struct values
func (*Encoder) RegisterCustomTypeFunc ¶ added in v1.4.0
func (e *Encoder) RegisterCustomTypeFunc(fn EncodeCustomTypeFunc, types ...interface{})
RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types NOTE: this method is not thread-safe it is intended that these all be registered prior to any parsing
func (*Encoder) RegisterTagNameFunc ¶
func (e *Encoder) RegisterTagNameFunc(fn TagNameFunc)
RegisterTagNameFunc registers a custom tag name parser function NOTE: This method is not thread-safe it is intended that these all be registered prior to any parsing
ADDITIONAL: once a custom function has been registered the default, or custom set, tag name is ignored and relies 100% on the function for the name data. The return value WILL BE CACHED and so return value must be consistent.
func (*Encoder) SetAnonymousMode ¶
func (e *Encoder) SetAnonymousMode(mode AnonymousMode)
SetAnonymousMode sets the mode the encoder should run Default is AnonymousEmbed
func (*Encoder) SetTagName ¶ added in v1.4.0
SetTagName sets the given tag name to be used by the encoder. Default is "form"
type InvalidDecoderError ¶
An InvalidDecoderError describes an invalid argument passed to Decode. (The argument passed to Decode must be a non-nil pointer.)
func (*InvalidDecoderError) Error ¶
func (e *InvalidDecoderError) Error() string
type InvalidEncodeError ¶
An InvalidEncodeError describes an invalid argument passed to Encode.
func (*InvalidEncodeError) Error ¶
func (e *InvalidEncodeError) Error() string
type TagNameFunc ¶
type TagNameFunc func(field reflect.StructField) string
TagNameFunc allows for adding of a custom tag name parser
       Source Files
      ¶
      Source Files
      ¶
    
  
       Directories
      ¶
      Directories
      ¶
    
    | Path | Synopsis | 
|---|---|
| _examples
       | |
| 
          
            decoder
            
            command
          
          
         | |
| 
          
            decoder-embedded
            
            command
          
          
         | |
| 
          
            encoder
            
            command
          
          
         | |
| 
          
            encoder-embedded
            
            command
          
          
         | |
| 
          
            encoder-omitempty
            
            command
          
          
         | 
