1

Introduction

gorilla/schema is a library for processing forms in the gorilla development kit. It provides a simple way to easily convert form data into structure objects, or convert structure objects into form data.

Quick to use

The code in this article uses Go Modules.

Create a directory and initialize:

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

Install the gorilla/schema library:

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

Let's take the previous login example:

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 call the schema.NewDecoder() method to create a decoder decoder . In the processor, first call r.ParseForm() parse the form data, then create a user object u , call decoder.Decode(&u, r.PostForm) to fill the object with the form data.

schema uses reflection to correspond to forms and structure fields. We can specify the correspondence between form data and fields through structure tags.

Above we use the decoder as a global variable in a package, because decoder will cache some structure metadata, and it is that is concurrently safe.

In the main function, we created the gorilla/mux route, registered the / root processing function, and used the middleware handlers.MethodHandler to register the /login of the GET and POST methods of the path 06101ef895f5a3 respectively. Then call http.Handle("/", r) forward all requests to gorilla/mux routing processing. Finally, start the Web server to accept the request.

coding

In addition to the server to decode the form data, schema can also be used on the client side to encode structure objects into the form data and send it to the server. We 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 usage of the decoder, first call schema.NewEncoder() create an encoder encoder , create a User type object u and form data object form , call encoder.Encode(u, form) to u into form . Then http.Client the PostForm method of transmitting a request. Read the response.

Custom type conversion

Currently schema supports the following types:

  • Boolean type: bool
  • Floating point number: 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 the above type
  • Slice: The element is a slice of the above type, or a pointer to a slice

Sometimes the client will combine a slice into a string and send it to the server, and the server needs to parse it into slices after receiving it:

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() register the conversion function of the corresponding type. The conversion function type is:

func(s string) reflect.Value

That is, the string value in the request is converted to a value that meets 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 deliberately sets the Hobbies field to a string and sends the request. The server uses the register func (s string) reflect.Value function to cut the string []string return.

Summarize

schema provides a simple way to get form data. By filling the data into the structure object, we can easily perform subsequent operations. schema library is relatively small, so you can try it if you don’t have much requirements for features~

If you find a fun and useful Go language library, welcome to submit an issue on the Go Daily Library GitHub😄

refer to

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

I

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

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


darjun
2.9k 声望358 粉丝