git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/schema/doc.go (about)

     1  // Copyright 2012 The Gorilla Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6  Package gorilla/schema fills a struct with form values.
     7  
     8  The basic usage is really simple. Given this struct:
     9  
    10  	type Person struct {
    11  		Name  string
    12  		Phone string
    13  	}
    14  
    15  ...we can fill it passing a map to the Decode() function:
    16  
    17  	values := map[string][]string{
    18  		"Name":  {"John"},
    19  		"Phone": {"999-999-999"},
    20  	}
    21  	person := new(Person)
    22  	decoder := schema.NewDecoder()
    23  	decoder.Decode(person, values)
    24  
    25  This is just a simple example and it doesn't make a lot of sense to create
    26  the map manually. Typically it will come from a http.Request object and
    27  will be of type url.Values, http.Request.Form, or http.Request.MultipartForm:
    28  
    29  	func MyHandler(w http.ResponseWriter, r *http.Request) {
    30  		err := r.ParseForm()
    31  
    32  		if err != nil {
    33  			// Handle error
    34  		}
    35  
    36  		decoder := schema.NewDecoder()
    37  		// r.PostForm is a map of our POST form values
    38  		err := decoder.Decode(person, r.PostForm)
    39  
    40  		if err != nil {
    41  			// Handle error
    42  		}
    43  
    44  		// Do something with person.Name or person.Phone
    45  	}
    46  
    47  Note: it is a good idea to set a Decoder instance as a package global,
    48  because it caches meta-data about structs, and an instance can be shared safely:
    49  
    50  	var decoder = schema.NewDecoder()
    51  
    52  To define custom names for fields, use a struct tag "schema". To not populate
    53  certain fields, use a dash for the name and it will be ignored:
    54  
    55  	type Person struct {
    56  		Name  string `schema:"name"`  // custom name
    57  		Phone string `schema:"phone"` // custom name
    58  		Admin bool   `schema:"-"`     // this field is never set
    59  	}
    60  
    61  The supported field types in the destination struct are:
    62  
    63    - bool
    64    - float variants (float32, float64)
    65    - int variants (int, int8, int16, int32, int64)
    66    - string
    67    - uint variants (uint, uint8, uint16, uint32, uint64)
    68    - struct
    69    - a pointer to one of the above types
    70    - a slice or a pointer to a slice of one of the above types
    71  
    72  Non-supported types are simply ignored, however custom types can be registered
    73  to be converted.
    74  
    75  To fill nested structs, keys must use a dotted notation as the "path" for the
    76  field. So for example, to fill the struct Person below:
    77  
    78  	type Phone struct {
    79  		Label  string
    80  		Number string
    81  	}
    82  
    83  	type Person struct {
    84  		Name  string
    85  		Phone Phone
    86  	}
    87  
    88  ...the source map must have the keys "Name", "Phone.Label" and "Phone.Number".
    89  This means that an HTML form to fill a Person struct must look like this:
    90  
    91  	<form>
    92  		<input type="text" name="Name">
    93  		<input type="text" name="Phone.Label">
    94  		<input type="text" name="Phone.Number">
    95  	</form>
    96  
    97  Single values are filled using the first value for a key from the source map.
    98  Slices are filled using all values for a key from the source map. So to fill
    99  a Person with multiple Phone values, like:
   100  
   101  	type Person struct {
   102  		Name   string
   103  		Phones []Phone
   104  	}
   105  
   106  ...an HTML form that accepts three Phone values would look like this:
   107  
   108  	<form>
   109  		<input type="text" name="Name">
   110  		<input type="text" name="Phones.0.Label">
   111  		<input type="text" name="Phones.0.Number">
   112  		<input type="text" name="Phones.1.Label">
   113  		<input type="text" name="Phones.1.Number">
   114  		<input type="text" name="Phones.2.Label">
   115  		<input type="text" name="Phones.2.Number">
   116  	</form>
   117  
   118  Notice that only for slices of structs the slice index is required.
   119  This is needed for disambiguation: if the nested struct also had a slice
   120  field, we could not translate multiple values to it if we did not use an
   121  index for the parent struct.
   122  
   123  There's also the possibility to create a custom type that implements the
   124  TextUnmarshaler interface, and in this case there's no need to register
   125  a converter, like:
   126  
   127  	type Person struct {
   128  	  Emails []Email
   129  	}
   130  
   131  	type Email struct {
   132  	  *mail.Address
   133  	}
   134  
   135  	func (e *Email) UnmarshalText(text []byte) (err error) {
   136  		e.Address, err = mail.ParseAddress(string(text))
   137  		return
   138  	}
   139  
   140  ...an HTML form that accepts three Email values would look like this:
   141  
   142  	<form>
   143  		<input type="email" name="Emails.0">
   144  		<input type="email" name="Emails.1">
   145  		<input type="email" name="Emails.2">
   146  	</form>
   147  */
   148  package schema