doc.go (8139B)
1 /* 2 Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values. 3 4 5 It has the following features: 6 7 - Primitives types cause zero allocations. 8 - Supports map of almost all types. 9 - Supports both Numbered and Normal arrays eg. "Array[0]" and just "Array" 10 with multiple values passed. 11 - Slice honours the specified index. eg. if "Slice[2]" is the only Slice 12 value passed down, it will be put at index 2; if slice isn't big enough 13 it will be expanded. 14 - Array honours the specified index. eg. if "Array[2]" is the only Array 15 value passed down, it will be put at index 2; if array isn't big enough 16 a warning will be printed and value ignored. 17 - Only creates objects as necessary eg. if no `array` or `map` values are 18 passed down, the `array` and `map` are left as their default values in 19 the struct. 20 - Allows for Custom Type registration. 21 - Handles time.Time using RFC3339 time format by default, 22 but can easily be changed by registering a Custom Type, see below. 23 - Handles Encoding & Decoding of almost all Go types eg. can Decode into 24 struct, array, map, int... and Encode a struct, array, map, int... 25 26 Common Questions 27 28 Questions 29 30 Does it support encoding.TextUnmarshaler? 31 No because TextUnmarshaler only accepts []byte but posted values can have 32 multiple values, so is not suitable. 33 34 Mixing array/slice with array[idx]/slice[idx], in which order are they parsed? 35 array/slice then array[idx]/slice[idx] 36 37 Supported Types 38 39 out of the box supported types 40 41 - string 42 - bool 43 - int, int8, int16, int32, int64 44 - uint, uint8, uint16, uint32, uint64 45 - float32, float64 46 - struct and anonymous struct 47 - interface{} 48 - time.Time` - by default using RFC3339 49 - a `pointer` to one of the above types 50 - slice, array 51 - map 52 - `custom types` can override any of the above types 53 - many other types may be supported inherently (eg. bson.ObjectId is 54 type ObjectId string, which will get populated by the string type 55 56 **NOTE**: map, struct and slice nesting are ad infinitum. 57 58 Usage 59 60 symbols 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. 64 (eg. `arrayfield[0]`, `mapfield[keyvalue]`) 65 66 html 67 68 <form method="POST"> 69 <input type="text" name="Name" value="joeybloggs"/> 70 <input type="text" name="Age" value="3"/> 71 <input type="text" name="Gender" value="Male"/> 72 <input type="text" name="Address[0].Name" value="26 Here Blvd."/> 73 <input type="text" name="Address[0].Phone" value="9(999)999-9999"/> 74 <input type="text" name="Address[1].Name" value="26 There Blvd."/> 75 <input type="text" name="Address[1].Phone" value="1(111)111-1111"/> 76 <input type="text" name="active" value="true"/> 77 <input type="text" name="MapExample[key]" value="value"/> 78 <input type="text" name="NestedMap[key][key]" value="value"/> 79 <input type="text" name="NestedArray[0][0]" value="value"/> 80 <input type="submit"/> 81 </form> 82 83 Example 84 85 example decoding the above HTML 86 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 example encoding 153 154 package main 155 156 import ( 157 "fmt" 158 "log" 159 160 "github.com/go-playground/form/v4" 161 ) 162 163 // Address contains address information 164 type Address struct { 165 Name string 166 Phone string 167 } 168 169 // User contains user information 170 type User struct { 171 Name string 172 Age uint8 173 Gender string 174 Address []Address 175 Active bool `form:"active"` 176 MapExample map[string]string 177 NestedMap map[string]map[string]string 178 NestedArray [][]string 179 } 180 181 // use a single instance of Encoder, it caches struct info 182 var encoder *form.Encoder 183 184 func main() { 185 encoder = form.NewEncoder() 186 187 user := User{ 188 Name: "joeybloggs", 189 Age: 3, 190 Gender: "Male", 191 Address: []Address{ 192 {Name: "26 Here Blvd.", Phone: "9(999)999-9999"}, 193 {Name: "26 There Blvd.", Phone: "1(111)111-1111"}, 194 }, 195 Active: true, 196 MapExample: map[string]string{"key": "value"}, 197 NestedMap: map[string]map[string]string{"key": {"key": "value"}}, 198 NestedArray: [][]string{{"value"}}, 199 } 200 201 // must pass a pointer 202 values, err := encoder.Encode(&user) 203 if err != nil { 204 log.Panic(err) 205 } 206 207 fmt.Printf("%#v\n", values) 208 } 209 210 211 Registering Custom Types 212 213 Decoder 214 215 decoder.RegisterCustomTypeFunc(func(vals []string) (interface{}, error) { 216 return time.Parse("2006-01-02", vals[0]) 217 }, time.Time{}) 218 219 ADDITIONAL: if a struct type is registered, the function will only be called 220 if a url.Value exists for the struct and not just the struct fields 221 eg. url.Values{"User":"Name%3Djoeybloggs"} will call the custom type function 222 with 'User' as the type, however url.Values{"User.Name":"joeybloggs"} will not. 223 224 Encoder 225 226 encoder.RegisterCustomTypeFunc(func(x interface{}) ([]string, error) { 227 return []string{x.(time.Time).Format("2006-01-02")}, nil 228 }, time.Time{}) 229 230 231 Ignoring Fields 232 233 you can tell form to ignore fields using `-` in the tag 234 235 type MyStruct struct { 236 Field string `form:"-"` 237 } 238 239 Omitempty 240 241 you can tell form to omit empty fields using `,omitempty` or `FieldName,omitempty` in the tag 242 243 type MyStruct struct { 244 Field string `form:",omitempty"` 245 Field2 string `form:"CustomFieldName,omitempty"` 246 } 247 248 249 Notes 250 251 To maximize compatibility with other systems the Encoder attempts 252 to avoid using array indexes in url.Values if at all possible. 253 254 eg. 255 256 // A struct field of 257 Field []string{"1", "2", "3"} 258 259 // will be output a url.Value as 260 "Field": []string{"1", "2", "3"} 261 262 and not 263 "Field[0]": []string{"1"} 264 "Field[1]": []string{"2"} 265 "Field[2]": []string{"3"} 266 267 // however there are times where it is unavoidable, like with pointers 268 i := int(1) 269 Field []*string{nil, nil, &i} 270 271 // to avoid index 1 and 2 must use index 272 "Field[2]": []string{"1"} 273 274 */ 275 package form