Introduction to the

Gorilla/Schema is the gorilla Development kit’s library for processing forms. It provides a simple way to easily convert form data into structured objects and from structured objects to form data.

Quick to use

The code in this article uses Go Modules.

Create directory and initialize:

$ mkdir gorilla/schema && cd gorilla/schema
$ go mod init github.com/darjun/go-daily-lib/gorilla/schema

To install the Gorilla/Schema library:

$ go get -u github.com/gorilla/schema

Let’s take the example from the previous login:

func index(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello World") } func login(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, `<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta  name="viewport" content="width=device-width, Initial -scale=1.0"> <title>Login</title> </head> <body> <form action="/ Login "method="post"> <label>Username:</label> <input name="username"><br> <label>Password:</label> <input name="password" type="password"><br> <button Type ="submit"> </button> </form> </body> </ HTML > ')} type User struct {Username string 'schema:" Username "' Password string `schema:"password"` } var ( decoder = schema.NewDecoder() ) func dologin(w http.ResponseWriter, r *http.Request) { r.ParseForm() u := User{} decoder.Decode(&u, r.PostForm) if u.Username == "dj" && u.Password == "handsome" { http.Redirect(w, r, "/", 301) return } http.Redirect(w, r, "/login", 301) } func main() { r := mux.NewRouter() r.HandleFunc("/", index) r.Handle("/login", handlers.MethodHandler{ "GET": http.HandlerFunc(login), "POST": http.HandlerFunc(dologin), }) log.Fatal(http.ListenAndServe(":8080", r)) }

First create a decoder by calling the schema.newdecoder () method. In the processor, r.ParseForm() is called to parse the form data, and then the user object U is created, which is populated with the form data by calling decoder.decode (&u, R.OstForm).

Schema uses reflection to map form and struct fields, and we can specify the mapping between form data and fields using the struct label.

Above we treat the decoder as a global variable within the package, because the decoder will cache some of the structure’s metadata and it is concurrency safe.

In the main function, we create gorilla/mux routing, register the/root handler, and use the middleware handlers.MethodHandler to register the handlers for the GET and POST methods of the path /login, respectively. It then calls http.handle (“/”, r) to leave all requests to Gorilla/Mux routing. Finally, start the Web server to accept the request.

coding

In addition to being used by the server to decode form data, schemas can also be used by the client to encode structural objects into the form data and send it to the server. Let’s write a program to log in to the server above:

var (
  encoder = schema.NewEncoder()
)

func main() {
  client := &http.Client{}
  form := url.Values{}

  u := &User{
    Username: "dj",
    Password: "handsome",
  }
  encoder.Encode(u, form)

  res, _ := client.PostForm("http://localhost:8080/login", form)
  data, _ := ioutil.ReadAll(res.Body)
  fmt.Println(string(data))
  res.Body.Close()
}

Similar to the decoder usage, first call schema.newencoder () to create an encoder encoder, create an object of type User u and form data object form, call encoder.encode (u, form) to Encode U into the form. The request is then sent using the PostForm method of http.Client. Read the response.

Custom type conversion

Currently, the following types of schemas are supported:

  • Boolean type:bool
  • Floating point Numbers:float32/float64
  • Signed integer:int/int8/int32/int64
  • Unsigned integer:uint/uint8/uint32/uint64
  • String:string
  • Structure: a structure composed of the above types
  • Pointer: pointer to one of the above types
  • Slice: The element is a slice of the above type, or a pointer to a slice

Sometimes a client will send a string from a slice to the server, and the server will parse the string:

type Person struct {
  Name    string   `schema:"name"`
  Age     int      `schema:"age"`
  Hobbies []string `schema:"hobbies"`
}

var (
  decoder = schema.NewDecoder()
)

func init() {
  decoder.RegisterConverter([]string{}, func(s string) reflect.Value {
    return reflect.ValueOf(strings.Split(s, ","))
  })
}

func doinfo(w http.ResponseWriter, r *http.Request) {
  r.ParseForm()
  p := Person{}
  decoder.Decode(&p, r.PostForm)

  fmt.Println(p)
  fmt.Fprintf(w, "Name:%s Age:%d Hobbies:%v", p.Name, p.Age, p.Hobbies)
}

Call decoder. RegisterConverter () registration of the corresponding type conversion function, transform function of type:

func(s string) reflect.Value

Convert the string value in the request into a value that satisfies our format.

Client request:

type Person struct {
  Name    string `schema:"name"`
  Age     int    `schema:"age"`
  Hobbies string `schema:"hobbies"`
}

var (
  encoder = schema.NewEncoder()
)

func main() {
  client := &http.Client{}
  form := url.Values{}

  p := &Person{
    Name:    "dj",
    Age:     18,
    Hobbies: "Game,Programming",
  }
  encoder.Encode(p, form)

  res, _ := client.PostForm("http://localhost:8080/info", form)
  data, _ := ioutil.ReadAll(res.Body)
  fmt.Println(string(data))
  res.Body.Close()
}

The client sends the request intentionally with the Hobbies field set to a string. The server will use the registered func (s string) reflect.value function to cut the string into a []string return.

conclusion

Schema provides an easy way to get form data, which we can easily follow up by populating the data into a structured object. Schema library is relatively small, do not have too many requirements for features can try ~

If you find a fun and useful Go library, please Go to GitHub and submit the issue😄

reference

  1. Gorilla/schema GitHub:github.com/gorilla/schema
  2. Go a library GitHub:https://github.com/darjun/go-daily-lib daily

I

My blog: https://darjun.github.io

Welcome to follow my wechat public account [GoUpUp], learn together, make progress together ~