Go gorilla / schema of one library per day

Time:2021-7-25

brief introduction

gorilla/schemaIs the library used to process forms in the gorilla development kit. It provides a simple way to convert form data into structure objects or structure objects into form data.

Quick 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

installgorilla/schemaLibrary:

$ 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" > login < / 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 callschema.NewDecoder()Method to create a decoderdecoder。 In the processor, callr.ParseForm()Parse the form data and create a user objectu, calldecoder.Decode(&u, r.PostForm)The form is populated with data from this object.

schemaUsing reflection to correspond to form and structure fields, we can specify the correspondence between form data and fields through structure labels.

Above, we regard the decoder as a global variable in the package becausedecoderMetadata of some structures is cached in, and it is concurrency safe

staymainFunction, we creategorilla/muxRouting, registration/Root processing function, using middlewarehandlers.MethodHandlerRegister paths separately/loginProcessor for get and post methods. Then callhttp.Handle("/", r)Submit all requests togorilla/muxRouting processing. Finally, start the web server to accept the request.

code

In addition to being used by the server to decode form data,schemaIt can also be used by the client to encode the structure object into the form data and send it to the server. We write a program to log in to the above server:

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, callschema.NewEncoder()Create an encoderencoder, create aUserObject of typeuAnd form data objectsform, callencoder.Encode(u, form)takeuCode toformYes. Then usehttp.ClientYesPostFormMethod to send a request. Read response.

Custom type conversion

at presentschemaThe following types are supported:

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

Sometimes the client will assemble a slice into a string and send it to the server. After receiving it, the server needs to parse it into slices:

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)
}

calldecoder.RegisterConverter()Register the conversion function of the corresponding type. The conversion function type is:

func(s string) reflect.Value

Convert the string value in the request 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 intentionallyHobbiesSet the field to a string and send the request. The server will use the registeredfunc (s string) reflect.ValueThe function cuts the string into[]stringreturn.

summary

schemaIt provides a simple way to obtain form data. By filling the data into the structure object, we can easily carry out subsequent operations.schemaThe library is relatively small. You can try it if you don’t have too many requirements for features~

If you find a fun and easy-to-use go language library, you are welcome to submit an issue on GitHub, the daily library of go

reference resources

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

I

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

Welcome to my WeChat official account, GoUpUp, learn together and make progress together.

Go gorilla / schema of one library per day