mirror of https://github.com/gorilla/schema
Mirror of https://github.com/gorilla/schema
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
4.0 KiB
148 lines
4.0 KiB
// Copyright 2012 The Gorilla Authors. All rights reserved. |
|
// Use of this source code is governed by a BSD-style |
|
// license that can be found in the LICENSE file. |
|
|
|
/* |
|
Package gorilla/schema fills a struct with form values. |
|
|
|
The basic usage is really simple. Given this struct: |
|
|
|
type Person struct { |
|
Name string |
|
Phone string |
|
} |
|
|
|
...we can fill it passing a map to the Decode() function: |
|
|
|
values := map[string][]string{ |
|
"Name": {"John"}, |
|
"Phone": {"999-999-999"}, |
|
} |
|
person := new(Person) |
|
decoder := schema.NewDecoder() |
|
decoder.Decode(person, values) |
|
|
|
This is just a simple example and it doesn't make a lot of sense to create |
|
the map manually. Typically it will come from a http.Request object and |
|
will be of type url.Values, http.Request.Form, or http.Request.MultipartForm: |
|
|
|
func MyHandler(w http.ResponseWriter, r *http.Request) { |
|
err := r.ParseForm() |
|
|
|
if err != nil { |
|
// Handle error |
|
} |
|
|
|
decoder := schema.NewDecoder() |
|
// r.PostForm is a map of our POST form values |
|
err := decoder.Decode(person, r.PostForm) |
|
|
|
if err != nil { |
|
// Handle error |
|
} |
|
|
|
// Do something with person.Name or person.Phone |
|
} |
|
|
|
Note: it is a good idea to set a Decoder instance as a package global, |
|
because it caches meta-data about structs, and an instance can be shared safely: |
|
|
|
var decoder = schema.NewDecoder() |
|
|
|
To define custom names for fields, use a struct tag "schema". To not populate |
|
certain fields, use a dash for the name and it will be ignored: |
|
|
|
type Person struct { |
|
Name string `schema:"name"` // custom name |
|
Phone string `schema:"phone"` // custom name |
|
Admin bool `schema:"-"` // this field is never set |
|
} |
|
|
|
The supported field types in the destination struct are: |
|
|
|
* bool |
|
* float variants (float32, float64) |
|
* int variants (int, int8, int16, int32, int64) |
|
* string |
|
* uint variants (uint, uint8, uint16, uint32, uint64) |
|
* struct |
|
* a pointer to one of the above types |
|
* a slice or a pointer to a slice of one of the above types |
|
|
|
Non-supported types are simply ignored, however custom types can be registered |
|
to be converted. |
|
|
|
To fill nested structs, keys must use a dotted notation as the "path" for the |
|
field. So for example, to fill the struct Person below: |
|
|
|
type Phone struct { |
|
Label string |
|
Number string |
|
} |
|
|
|
type Person struct { |
|
Name string |
|
Phone Phone |
|
} |
|
|
|
...the source map must have the keys "Name", "Phone.Label" and "Phone.Number". |
|
This means that an HTML form to fill a Person struct must look like this: |
|
|
|
<form> |
|
<input type="text" name="Name"> |
|
<input type="text" name="Phone.Label"> |
|
<input type="text" name="Phone.Number"> |
|
</form> |
|
|
|
Single values are filled using the first value for a key from the source map. |
|
Slices are filled using all values for a key from the source map. So to fill |
|
a Person with multiple Phone values, like: |
|
|
|
type Person struct { |
|
Name string |
|
Phones []Phone |
|
} |
|
|
|
...an HTML form that accepts three Phone values would look like this: |
|
|
|
<form> |
|
<input type="text" name="Name"> |
|
<input type="text" name="Phones.0.Label"> |
|
<input type="text" name="Phones.0.Number"> |
|
<input type="text" name="Phones.1.Label"> |
|
<input type="text" name="Phones.1.Number"> |
|
<input type="text" name="Phones.2.Label"> |
|
<input type="text" name="Phones.2.Number"> |
|
</form> |
|
|
|
Notice that only for slices of structs the slice index is required. |
|
This is needed for disambiguation: if the nested struct also had a slice |
|
field, we could not translate multiple values to it if we did not use an |
|
index for the parent struct. |
|
|
|
There's also the possibility to create a custom type that implements the |
|
TextUnmarshaler interface, and in this case there's no need to register |
|
a converter, like: |
|
|
|
type Person struct { |
|
Emails []Email |
|
} |
|
|
|
type Email struct { |
|
*mail.Address |
|
} |
|
|
|
func (e *Email) UnmarshalText(text []byte) (err error) { |
|
e.Address, err = mail.ParseAddress(string(text)) |
|
return |
|
} |
|
|
|
...an HTML form that accepts three Email values would look like this: |
|
|
|
<form> |
|
<input type="email" name="Emails.0"> |
|
<input type="email" name="Emails.1"> |
|
<input type="email" name="Emails.2"> |
|
</form> |
|
*/ |
|
package schema
|
|
|