A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://github.com/go-playground/form below:

go-playground/form: :steam_locomotive: Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. Dual Array and Full map support.

Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values.

It has the following features:

Common Questions

Supported Types ( out of the box )

NOTE: map, struct and slice nesting are ad infinitum.

Use go get.

go get github.com/go-playground/form

Then import the form package into your own code.

import "github.com/go-playground/form/v4"
<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>

Decoding

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"},
	}
}

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)
}

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{})

you can tell form to ignore fields using - in the tag

type MyStruct struct {
	Field string `form:"-"`
}

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"`
}

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"}
Run on M1 MacBook Pro using go version go1.20.6 darwin/amd64

NOTE: the 1 allocation and B/op in the first 4 decodes is actually the struct allocating when passing it in, so primitives are actually zero allocation.

go test -run=NONE -bench=. -benchmem=true ./...
goos: darwin
goarch: arm64
pkg: github.com/go-playground/form/v4/benchmarks
BenchmarkSimpleUserDecodeStruct-8                                8704111               121.1 ns/op            64 B/op          1 allocs/op
BenchmarkSimpleUserDecodeStructParallel-8                       35916134                32.89 ns/op           64 B/op          1 allocs/op
BenchmarkSimpleUserEncodeStruct-8                                3746173               320.7 ns/op           485 B/op         10 allocs/op
BenchmarkSimpleUserEncodeStructParallel-8                        7293147               180.0 ns/op           485 B/op         10 allocs/op
BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8              2993259               400.5 ns/op            96 B/op          1 allocs/op
BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8     13023300                97.70 ns/op           96 B/op          1 allocs/op
BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8               643202              1767 ns/op            2977 B/op         35 allocs/op
BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8      1000000              1202 ns/op            2978 B/op         35 allocs/op
BenchmarkComplexArrayDecodeStructAllTypes-8                       172630              6822 ns/op            2008 B/op        121 allocs/op
BenchmarkComplexArrayDecodeStructAllTypesParallel-8               719788              1735 ns/op            2009 B/op        121 allocs/op
BenchmarkComplexArrayEncodeStructAllTypes-8                       197052              5839 ns/op            7087 B/op        104 allocs/op
BenchmarkComplexArrayEncodeStructAllTypesParallel-8               348039              3247 ns/op            7089 B/op        104 allocs/op
BenchmarkComplexMapDecodeStructAllTypes-8                         139246              8550 ns/op            5313 B/op        130 allocs/op
BenchmarkComplexMapDecodeStructAllTypesParallel-8                 409018              3143 ns/op            5317 B/op        130 allocs/op
BenchmarkComplexMapEncodeStructAllTypes-8                         208833              5515 ns/op            4257 B/op        103 allocs/op
BenchmarkComplexMapEncodeStructAllTypesParallel-8                 523833              2182 ns/op            4258 B/op        103 allocs/op
BenchmarkDecodeNestedStruct-8                                     807690              1408 ns/op             344 B/op         14 allocs/op
BenchmarkDecodeNestedStructParallel-8                            3409441               359.6 ns/op           344 B/op         14 allocs/op
BenchmarkEncodeNestedStruct-8                                    1488520               803.6 ns/op           653 B/op         16 allocs/op
BenchmarkEncodeNestedStructParallel-8                            3570204               346.6 ns/op           653 B/op         16 allocs/op

Competitor benchmarks can be found here

Here is a list of software that compliments using this library post decoding.

Distributed under MIT License, please see license file in code for more details.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4