gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

README.md (12205B)


      1 Package form
      2 ============
      3 <img align="right" src="https://raw.githubusercontent.com/go-playground/form/master/logo.jpg">![Project status](https://img.shields.io/badge/version-4.2.0-green.svg)
      4 [![Build Status](https://github.com/go-playground/form/actions/workflows/workflow.yml/badge.svg)](https://github.com/go-playground/form/actions/workflows/workflow.yml)
      5 [![Coverage Status](https://coveralls.io/repos/github/go-playground/form/badge.svg?branch=master)](https://coveralls.io/github/go-playground/form?branch=master)
      6 [![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/form)](https://goreportcard.com/report/github.com/go-playground/form)
      7 [![GoDoc](https://godoc.org/github.com/go-playground/form?status.svg)](https://godoc.org/github.com/go-playground/form)
      8 ![License](https://img.shields.io/dub/l/vibe-d.svg)
      9 [![Gitter](https://badges.gitter.im/go-playground/form.svg)](https://gitter.im/go-playground/form?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
     10 
     11 Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values.
     12 
     13 It has the following features:
     14 
     15 - Supports map of almost all types.
     16 - Supports both Numbered and Normal arrays eg. `"Array[0]"` and just `"Array"` with multiple values passed.
     17 - 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.
     18 - 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.
     19 - 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.
     20 - Allows for Custom Type registration.
     21 - Handles time.Time using RFC3339 time format by default, but can easily be changed by registering a Custom Type, see below.
     22 - Handles Encoding & Decoding of almost all Go types eg. can Decode into struct, array, map, int... and Encode a struct, array, map, int...
     23 
     24 Common Questions
     25 
     26 - Does it support encoding.TextUnmarshaler? No because TextUnmarshaler only accepts []byte but posted values can have multiple values, so is not suitable.
     27 - Mixing `array/slice` with `array[idx]/slice[idx]`, in which order are they parsed? `array/slice` then `array[idx]/slice[idx]`
     28 
     29 Supported Types ( out of the box )
     30 ----------
     31 
     32 * `string`
     33 * `bool`
     34 * `int`, `int8`, `int16`, `int32`, `int64`
     35 * `uint`, `uint8`, `uint16`, `uint32`, `uint64`
     36 * `float32`, `float64`
     37 * `struct` and `anonymous struct`
     38 * `interface{}`
     39 * `time.Time` - by default using RFC3339
     40 * a `pointer` to one of the above types
     41 * `slice`, `array`
     42 * `map`
     43 * `custom types` can override any of the above types
     44 * many other types may be supported inherently
     45 
     46 **NOTE**: `map`, `struct` and `slice` nesting are ad infinitum.
     47 
     48 Installation
     49 ------------
     50 
     51 Use go get.
     52 
     53 	go get github.com/go-playground/form
     54 
     55 Then import the form package into your own code.
     56 
     57 	import "github.com/go-playground/form/v4"
     58 
     59 Usage
     60 -----
     61 
     62 - Use symbol `.` for separating fields/structs. (eg. `structfield.field`)
     63 - Use `[index or key]` for access to index of a slice/array or key for map. (eg. `arrayfield[0]`, `mapfield[keyvalue]`)
     64 
     65 ```html
     66 <form method="POST">
     67   <input type="text" name="Name" value="joeybloggs"/>
     68   <input type="text" name="Age" value="3"/>
     69   <input type="text" name="Gender" value="Male"/>
     70   <input type="text" name="Address[0].Name" value="26 Here Blvd."/>
     71   <input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
     72   <input type="text" name="Address[1].Name" value="26 There Blvd."/>
     73   <input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
     74   <input type="text" name="active" value="true"/>
     75   <input type="text" name="MapExample[key]" value="value"/>
     76   <input type="text" name="NestedMap[key][key]" value="value"/>
     77   <input type="text" name="NestedArray[0][0]" value="value"/>
     78   <input type="submit"/>
     79 </form>
     80 ```
     81 
     82 Examples
     83 -------
     84 
     85 Decoding
     86 ```go
     87 package main
     88 
     89 import (
     90 	"fmt"
     91 	"log"
     92 	"net/url"
     93 
     94 	"github.com/go-playground/form/v4"
     95 )
     96 
     97 // Address contains address information
     98 type Address struct {
     99 	Name  string
    100 	Phone string
    101 }
    102 
    103 // User contains user information
    104 type User struct {
    105 	Name        string
    106 	Age         uint8
    107 	Gender      string
    108 	Address     []Address
    109 	Active      bool `form:"active"`
    110 	MapExample  map[string]string
    111 	NestedMap   map[string]map[string]string
    112 	NestedArray [][]string
    113 }
    114 
    115 // use a single instance of Decoder, it caches struct info
    116 var decoder *form.Decoder
    117 
    118 func main() {
    119 	decoder = form.NewDecoder()
    120 
    121 	// this simulates the results of http.Request's ParseForm() function
    122 	values := parseForm()
    123 
    124 	var user User
    125 
    126 	// must pass a pointer
    127 	err := decoder.Decode(&user, values)
    128 	if err != nil {
    129 		log.Panic(err)
    130 	}
    131 
    132 	fmt.Printf("%#v\n", user)
    133 }
    134 
    135 // this simulates the results of http.Request's ParseForm() function
    136 func parseForm() url.Values {
    137 	return url.Values{
    138 		"Name":                []string{"joeybloggs"},
    139 		"Age":                 []string{"3"},
    140 		"Gender":              []string{"Male"},
    141 		"Address[0].Name":     []string{"26 Here Blvd."},
    142 		"Address[0].Phone":    []string{"9(999)999-9999"},
    143 		"Address[1].Name":     []string{"26 There Blvd."},
    144 		"Address[1].Phone":    []string{"1(111)111-1111"},
    145 		"active":              []string{"true"},
    146 		"MapExample[key]":     []string{"value"},
    147 		"NestedMap[key][key]": []string{"value"},
    148 		"NestedArray[0][0]":   []string{"value"},
    149 	}
    150 }
    151 ```
    152 
    153 Encoding
    154 ```go
    155 package main
    156 
    157 import (
    158 	"fmt"
    159 	"log"
    160 
    161 	"github.com/go-playground/form/v4"
    162 )
    163 
    164 // Address contains address information
    165 type Address struct {
    166 	Name  string
    167 	Phone string
    168 }
    169 
    170 // User contains user information
    171 type User struct {
    172 	Name        string
    173 	Age         uint8
    174 	Gender      string
    175 	Address     []Address
    176 	Active      bool `form:"active"`
    177 	MapExample  map[string]string
    178 	NestedMap   map[string]map[string]string
    179 	NestedArray [][]string
    180 }
    181 
    182 // use a single instance of Encoder, it caches struct info
    183 var encoder *form.Encoder
    184 
    185 func main() {
    186 	encoder = form.NewEncoder()
    187 
    188 	user := User{
    189 		Name:   "joeybloggs",
    190 		Age:    3,
    191 		Gender: "Male",
    192 		Address: []Address{
    193 			{Name: "26 Here Blvd.", Phone: "9(999)999-9999"},
    194 			{Name: "26 There Blvd.", Phone: "1(111)111-1111"},
    195 		},
    196 		Active:      true,
    197 		MapExample:  map[string]string{"key": "value"},
    198 		NestedMap:   map[string]map[string]string{"key": {"key": "value"}},
    199 		NestedArray: [][]string{{"value"}},
    200 	}
    201 
    202 	// must pass a pointer
    203 	values, err := encoder.Encode(&user)
    204 	if err != nil {
    205 		log.Panic(err)
    206 	}
    207 
    208 	fmt.Printf("%#v\n", values)
    209 }
    210 ```
    211 
    212 Registering Custom Types
    213 --------------
    214 
    215 Decoder
    216 ```go
    217 decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) {
    218 	return time.Parse("2006-01-02", vals[0])
    219 }, time.Time{})
    220 ```
    221 ADDITIONAL: if a struct type is registered, the function will only be called if a url.Value exists for
    222 the struct and not just the struct fields eg. url.Values{"User":"Name%3Djoeybloggs"} will call the
    223 custom type function with 'User' as the type, however url.Values{"User.Name":"joeybloggs"} will not.
    224 
    225 
    226 Encoder
    227 ```go
    228 encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) {
    229 	return []string{x.(time.Time).Format("2006-01-02")}, nil
    230 }, time.Time{})
    231 ```
    232 
    233 Ignoring Fields
    234 --------------
    235 you can tell form to ignore fields using `-` in the tag
    236 ```go
    237 type MyStruct struct {
    238 	Field string `form:"-"`
    239 }
    240 ```
    241 
    242 Omitempty
    243 --------------
    244 you can tell form to omit empty fields using `,omitempty` or `FieldName,omitempty` in the tag
    245 ```go
    246 type MyStruct struct {
    247 	Field  string `form:",omitempty"`
    248 	Field2 string `form:"CustomFieldName,omitempty"`
    249 }
    250 ```
    251 
    252 Notes
    253 ------
    254 To maximize compatibility with other systems the Encoder attempts
    255 to avoid using array indexes in url.Values if at all possible.
    256 
    257 eg.
    258 ```go
    259 // A struct field of
    260 Field []string{"1", "2", "3"}
    261 
    262 // will be output a url.Value as
    263 "Field": []string{"1", "2", "3"}
    264 
    265 and not
    266 "Field[0]": []string{"1"}
    267 "Field[1]": []string{"2"}
    268 "Field[2]": []string{"3"}
    269 
    270 // however there are times where it is unavoidable, like with pointers
    271 i := int(1)
    272 Field []*string{nil, nil, &i}
    273 
    274 // to avoid index 1 and 2 must use index
    275 "Field[2]": []string{"1"}
    276 ```
    277 
    278 Benchmarks
    279 ------
    280 ###### Run on MacBook Pro (15-inch, 2017) using go version go1.10.1 darwin/amd64
    281 
    282 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.
    283 
    284 ```go
    285 go test -run=NONE -bench=. -benchmem=true
    286 goos: darwin
    287 goarch: amd64
    288 pkg: github.com/go-playground/form/benchmarks
    289 
    290 BenchmarkSimpleUserDecodeStruct-8                                    	 5000000	       236 ns/op	      64 B/op	       1 allocs/op
    291 BenchmarkSimpleUserDecodeStructParallel-8                            	20000000	        82.1 ns/op	      64 B/op	       1 allocs/op
    292 BenchmarkSimpleUserEncodeStruct-8                                    	 2000000	       627 ns/op	     485 B/op	      10 allocs/op
    293 BenchmarkSimpleUserEncodeStructParallel-8                            	10000000	       223 ns/op	     485 B/op	      10 allocs/op
    294 BenchmarkPrimitivesDecodeStructAllPrimitivesTypes-8                  	 2000000	       724 ns/op	      96 B/op	       1 allocs/op
    295 BenchmarkPrimitivesDecodeStructAllPrimitivesTypesParallel-8          	10000000	       246 ns/op	      96 B/op	       1 allocs/op
    296 BenchmarkPrimitivesEncodeStructAllPrimitivesTypes-8                  	  500000	      3187 ns/op	    2977 B/op	      36 allocs/op
    297 BenchmarkPrimitivesEncodeStructAllPrimitivesTypesParallel-8          	 1000000	      1106 ns/op	    2977 B/op	      36 allocs/op
    298 BenchmarkComplexArrayDecodeStructAllTypes-8                          	  100000	     13748 ns/op	    2248 B/op	     121 allocs/op
    299 BenchmarkComplexArrayDecodeStructAllTypesParallel-8                  	  500000	      4313 ns/op	    2249 B/op	     121 allocs/op
    300 BenchmarkComplexArrayEncodeStructAllTypes-8                          	  200000	     10758 ns/op	    7113 B/op	     104 allocs/op
    301 BenchmarkComplexArrayEncodeStructAllTypesParallel-8                  	  500000	      3532 ns/op	    7113 B/op	     104 allocs/op
    302 BenchmarkComplexMapDecodeStructAllTypes-8                            	  100000	     17644 ns/op	    5305 B/op	     130 allocs/op
    303 BenchmarkComplexMapDecodeStructAllTypesParallel-8                    	  300000	      5470 ns/op	    5308 B/op	     130 allocs/op
    304 BenchmarkComplexMapEncodeStructAllTypes-8                            	  200000	     11155 ns/op	    6971 B/op	     129 allocs/op
    305 BenchmarkComplexMapEncodeStructAllTypesParallel-8                    	  500000	      3768 ns/op	    6971 B/op	     129 allocs/op
    306 BenchmarkDecodeNestedStruct-8                                        	  500000	      2462 ns/op	     384 B/op	      14 allocs/op
    307 BenchmarkDecodeNestedStructParallel-8                                	 2000000	       814 ns/op	     384 B/op	      14 allocs/op
    308 BenchmarkEncodeNestedStruct-8                                        	 1000000	      1483 ns/op	     693 B/op	      16 allocs/op
    309 BenchmarkEncodeNestedStructParallel-8                                	 3000000	       525 ns/op	     693 B/op	      16 allocs/op
    310 ```
    311 
    312 Competitor benchmarks can be found [here](https://github.com/go-playground/form/blob/master/benchmarks/benchmarks.md)
    313 
    314 Complimentary Software
    315 ----------------------
    316 
    317 Here is a list of software that compliments using this library post decoding.
    318 
    319 * [Validator](https://github.com/go-playground/validator) - Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving.
    320 * [mold](https://github.com/go-playground/mold) - Is a general library to help modify or set data within data structures and other objects.
    321 
    322 Package Versioning
    323 ----------
    324 I'm jumping on the vendoring bandwagon, you should vendor this package as I will not
    325 be creating different version with gopkg.in like allot of my other libraries.
    326 
    327 Why? because my time is spread pretty thin maintaining all of the libraries I have + LIFE,
    328 it is so freeing not to worry about it and will help me keep pouring out bigger and better
    329 things for you the community.
    330 
    331 License
    332 ------
    333 Distributed under MIT License, please see license file in code for more details.