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.
- Slice honours the specified index. eg. if "Slice[2]" is the only Slice value passed down, it will be put at index 2; if slice isn't big enough it will be expanded.
- 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 a warning will be printed and value ignored.
- 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.
Mixing array/slice with array[idx]/slice[idx], in which order are they parsed?
array/slice then array[idx]/slice[idx]
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/v4"
)
// 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/v4"
)
// 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) SetAnonymousMode(mode AnonymousMode)
- func (d *Decoder) SetMaxArraySize(size uint)
- func (d *Decoder) SetMode(mode Mode)
- func (d *Decoder) SetNamespacePrefix(namespacePrefix string)
- func (d *Decoder) SetNamespaceSuffix(namespaceSuffix string)
- 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) SetNamespacePrefix(namespacePrefix string)
- func (e *Encoder) SetNamespaceSuffix(namespaceSuffix string)
- 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 ¶
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) SetAnonymousMode ¶ added in v4.5.0
func (d *Decoder) SetAnonymousMode(mode AnonymousMode)
SetAnonymousMode sets how embedded structs are decoded. Default is AnonymousEmbed, which also fills promoted fields from the parent namespace. AnonymousSeparate only sets an embedded field from its own namespace (e.g. "A.Field"), matching Encoder.SetAnonymousMode.
func (*Decoder) SetMaxArraySize ¶
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) SetNamespacePrefix ¶ added in v4.2.0
SetNamespacePrefix sets a struct namespace prefix.
func (*Decoder) SetNamespaceSuffix ¶ added in v4.2.0
SetNamespaceSuffix sets a struct namespace suffix.
func (*Decoder) SetTagName ¶
SetTagName sets the given tag name to be used by the decoder. Default is "form"
type EncodeCustomTypeFunc ¶
EncodeCustomTypeFunc allows for registering/overriding types to be parsed.
type EncodeErrors ¶
EncodeErrors is a map of errors encountered during form encoding
func (EncodeErrors) Error ¶
func (e EncodeErrors) Error() string
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder is the main encode instance
func NewEncoder ¶
func NewEncoder() *Encoder
NewEncoder creates a new encoder instance with sane defaults
func (*Encoder) RegisterCustomTypeFunc ¶
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) SetNamespacePrefix ¶ added in v4.2.0
SetNamespacePrefix sets a struct namespace prefix.
func (*Encoder) SetNamespaceSuffix ¶ added in v4.2.0
SetNamespaceSuffix sets a struct namespace suffix.
func (*Encoder) SetTagName ¶
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
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
_examples
|
|
|
decoder
command
|
|
|
decoder-embedded
command
|
|
|
encoder
command
|
|
|
encoder-embedded
command
|
|
|
encoder-omitempty
command
|
