He travelled eighty thousand miles a day, surveying the sky and seeing a thousand rivers

Go up nine days to pull a month, next five oceans catch turtle, The self-confidence of Chinese people from can be impossible step by step become reality, once blockade, suppress, ridicule will eventually become the milestone of each foot on the way forward, no matter how rough the road before, still can have brilliant tomorrow will eventually come.

Gin’s Hello World

import "github.com/gin-gonic/gin"

func main() {

	r := gin.Default()
	r.GET("/ping", func(c *gin.Context){
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})
	r.Run()
}
Copy the code

2. Customize the HTTP configuration

func main() {
    router := gin.Default()

    s := &http.Server{
        Addr:           ":8080",
        Handler:        router,
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   10 * time.Second,
        MaxHeaderBytes: 1 << 20,
    }
    s.ListenAndServe()
}
Copy the code

3. Custom middleware

Func Logger() gin.HandlerFunc {return func(c *gin.Context) {t := time.now () // set example variable c.set ("example", "12345") latency := time.since (t) log.print (latency); log.Println(status) } } func main() { r := gin.New() r.Use(Logger()) r.GET("/test", func(c *gin.Context) { example := c.MustGet("example").(string) log.Println(example) }) r.Run(":8080") }Copy the code

4. Routing group

Func main() {router := gin.Default() // Simple routing group: v1 v1 := router.Group("/v1") { v1.POST("/login", loginEndpoint) v1.POST("/submit", submitEndpoint) v1.POST("/read", ReadEndpoint)} // Simple routing group: v2 v2 := router.Group("/v2") { v2.POST("/login", loginEndpoint) v2.POST("/submit", submitEndpoint) v2.POST("/read", readEndpoint) } router.Run(":8080") }Copy the code

5. Run multiple services

package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" ) var ( g errgroup.Group ) func router01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 01", }, ) }) return e } func router02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 02", }, ) }) return e } func main() { server01 := &http.Server{ Addr: ":8080", Handler: router01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: ":8081", Handler: router02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { return server01.ListenAndServe() }) g.Go(func() error { return server02.ListenAndServe() }) if err  := g.Wait(); err ! = nil { log.Fatal(err) } }Copy the code

6. Implementation of RESTFUI API

func getting(c *gin.Context) { c.JSON(200, gin.H{ "message": "getting method!" , }) } func posting(c *gin.Context) { c.JSON(200, gin.H{ "message": "posting method!" , }) } func putting(c *gin.Context) { c.JSON(200, gin.H{ "message": "putting method!" , }) } func deleting(c *gin.Context) { c.JSON(200, gin.H{ "message": "deleting method!" , }) } func patching(c *gin.Context) { c.JSON(200, gin.H{ "message": "patching method!" , }) } func head(c *gin.Context) { c.JSON(200, gin.H{ "message": "head method!" , }) } func options(c *gin.Context) { c.JSON(200, gin.H{ "message": "options method!" , }) } func main() { r := gin.Default() r.GET("/someGET", getting) r.POST("/somePOST", posting) r.PUT("somePUT", putting) r.DELETE("/someDELETE", deleting) r.PATCH("/somePATCH", patching) r.HEAD("/someHEAD", head) r.OPTIONS("/someOPTIONS", options) r.Run(":8090") }Copy the code

7. Route parameters

// The following routes match (otherwise, the routing rule is single, Func main() {r := gin.Default() r.et ("/users/:id", func(c *gin.Context) { id := c.Param("id") c.String(200, "The user id is %s", Id)}) r.run (":8080")} // Routing rule with *, which matches all /users/123 match /users/ ha match /users/123/go match /users/ match func main() {r := gin.Default() r.GET("/users/*id", func(c *gin.Context) { id := c.Param("id") c.String(200, "The user id is %s", Id)}) r.run (":8080")} // Query string parameter func main() {r := gin.Default() // obtain parameter from url connection: XXX? firstname=Jane&lastname=Doe r.GET("/welcome", func(c *gin.Context) { firstname := c.DefaultQuery("firstname", "Guest") lastname := c.Query("lastname") c.String(http.StatusOK, "Hello %s %s", firstname, }) r.run (":8080")} // Map query string or form data func main() {r := gin.Default() r.post ("/post", func(c *gin.Context) { ids := c.QueryMap("ids") names := c.PostFormMap("names") fmt.Printf("ids: %v; names: %v", ids, names) }) router.Run(":8080") } POST /post? Ids [a] = 1234 & ids [b] = HTTP / 1.1 the content-type: hello! Application /x-www-form-urlencoded names[first]=thinkerou&names[second]=tianou //post form parameters obtain func main() {r := gin.Default() router.POST("/post", func(c *gin.Context) { page := c.DefaultQuery("page", "0") name := c.PostForm("name") message := c.PostForm("message") fmt.Printf("page: %s; name: %s; message: %s", page, name, Run(":8080")} // bind URI type Person struct {ID string 'URI :" ID "binding:"required,uuid"' Name string `uri:"name" binding:"required"` } func main() { r := gin.Default() r.GET("/:name/:id", func(c *gin.Context) { var person Person if err := c.ShouldBindUri(&person); err ! = nil { c.JSON(400, gin.H{"msg": err}) return } c.JSON(200, gin.H{"name": person.Name, "uuid": Person.id})}) r.run (":8088")} type StructA struct {FieldA string 'form:" field_A "'} type StructB struct { NestedStruct StructA FieldB string `form:"field_b"` } type StructC struct { NestedStructPointer *StructA FieldC string  `form:"field_c"` } type StructD struct { NestedAnonyStruct struct { FieldX string `form:"field_x"` } FieldD string `form:"field_d"` } func GetDataB(c *gin.Context) { var b StructB c.Bind(&b) c.JSON(200, gin.H{ "a": b.NestedStruct, "b": b.FieldB, }) } func GetDataC(c *gin.Context) { var b StructC c.Bind(&b) c.JSON(200, gin.H{ "a": b.NestedStructPointer, "c": b.FieldC, }) } func GetDataD(c *gin.Context) { var b StructD c.Bind(&b) c.JSON(200, gin.H{ "x": b.NestedAnonyStruct, "d": b.FieldD, }) } func main() { r := gin.Default() r.GET("/getb", GetDataB) r.GET("/getc", GetDataC) r.GET("/getd", GetDataD) r.Run() }Copy the code

Gin for JSON processing

//AsciiJSON func main() { r := gin.Default() r.GET("/someJSON", Func (c * gin in the Context) {data: = map [string] interface {} {" lang ":" the language ", "tag" : "< br >",} / / output: {"lang":"GO\u8bed\u8a00","tag":"\u003cbr\u003e"} c.AsciiJSON(http.StatusOK, Data)}) r.run (":8080")} //PureJSON func main() {r := gin.Default() // Provide unicode entities r.git ("/json", func(c *gin.Context) { c.JSON(200, gin.H{ "html": "<b>Hello, world! < / b > ",}}) / / r. gutierrez ET provide literal characters ("/purejson ", func (c * gin in the Context) {c.P ureJSON (200, gin. H {" HTML ":" < b > Hello, world! < / b > ",}}) r.R UN (" : "8080)} / / SecureJSON (prefixed while ()) Func main() {r := gin.Default() // You can also use your own SecureJSON prefix // r.securejsonPrefix (")]}',\n") r.git ("/someJSON", Func (c *gin.Context) {names := []string{" Lena ", "Austin ", "foo"} // will print: while(1); ["lena","austin","foo"] c.SecureJSON(http.StatusOK, names) }) r.Run(":8080") }Copy the code

7. Upload and download files

/ / the single file upload func main () {router: = gin. Default () / / for multipart forms set lower memory limit (Default is 32 MiB) / / router. MaxMultipartMemory = POST("/upload", func(c *gin.Context) {// single file file, _ := c.folmfile ("file") log.println (file.filename) // Upload the file to the specified directory // c.saveuploadedfile (file, dst) c.String(http.StatusOK, fmt.Sprintf("'%s' uploaded!" . File. The Filename))}) of the router. The Run (" : "8080)} curl -x POST http://localhost:8080/upload - F" file = @ / Users/appleboy/test. The zip" - H "content-type: Multipart /form-data" // Upload of multiple files func main() {router := gin.Default() // Set a low memory limit for multipart Forms (32 MiB by Default) // router.MaxMultipartMemory = 8 << 20 // 8 MiB router.POST("/upload", func(c *gin.Context) { // Multipart form form, _ := c.MultipartForm() files := form.File["upload[]"] for _, File := range files {log.println (file.filename) // Upload the file to the specified directory // c.saveuploadedfile (file, dst) } c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!" . len(files))) }) router.Run(":8080") } curl -X POST http://localhost:8080/upload \ -F "upload[]=@/Users/appleboy/test1.zip" \ -F "upload[]=@/Users/appleboy/test2.zip" \ -H "Content-Type: Multipart /form-data" // File download func main() {r := gin.Default() r.et ("/someDataFromReader", func(c *gin.Context) { response, err := http.Get("https://raw.githubusercontent.com/gin-gonic/logo/master/color.png") if err ! = nil || response.StatusCode ! = http.StatusOK { c.Status(http.StatusServiceUnavailable) return } reader := response.Body contentLength := response.ContentLength contentType := response.Header.Get("Content-Type") extraHeaders := map[string]string{ "Content-Disposition": `attachment; filename="gopher.png"`, } c.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders) }) r.Run(":8080") }Copy the code

8. Setting and obtaining cookies

func main() { r := gin.Default() r.GET("/cookie", func(c *gin.Context) { cookie, err := c.Cookie("gin_cookie") if err ! = nil { cookie = "NotSet" c.SetCookie("gin_cookie", "test", 3600, "/", "localhost", false, true) } fmt.Printf("Cookie value: %s \n", cookie) }) r.Run() }Copy the code

redirect

/ / r. gutierrez ET for HTTP redirect ("/test ", the func (c * gin in the Context) {c.R edirect (HTTP. StatusMovedPermanently, "Http://www.google.com/")}) / / r. gutierrez ET for the internal routing redirection ("/test ", func(c *gin.Context) { c.Request.URL.Path = "/test2" r.HandleContext(c) }) r.GET("/test2", func(c *gin.Context) { c.JSON(200, gin.H{"hello": "world"}) })Copy the code

10. Run multiple services

package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" ) var ( g errgroup.Group ) func router01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 01", }, ) }) return e } func router02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 02", }, ) }) return e } func main() { server01 := &http.Server{ Addr: ":8080", Handler: router01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: ":8081", Handler: router02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { return server01.ListenAndServe() }) g.Go(func() error { return server02.ListenAndServe() }) if err  := g.Wait(); err ! = nil { log.Fatal(err) } }Copy the code

11. Output of XML, JSON, YAML, ProtoBuf data formats

Func main() {r := gin.Default() //json output format r.git ("/someJSON", func(c *gin.Context) {c.son (http.statusok, gin.H{"message": "hey", "status": http.StatusOK}) }) r.GET("/moreJSON", func(c *gin.Context) { var msg struct { Name string `json:"user"` Message string Number int } msg.Name = "Lena" MSG.Message = "hey" MSG.Number = 123 // Note that MSG.Name is changed to "user" in JSON // will output: {"user": "Lena", "Message": "hey", "Number": 123} c.son (http.statusok, MSG)}) // XML output format r.git ("/someXML", func(c *gin.Context) {c.xml (http.statusok, MSG)} gin.H{"message": "hey", "status": Http.statusok})}) // yamL output format r.git ("/someYAML", func(c *gin.Context) {c.yaml (http.statusok, gin.H{"message": "hey", "status": HTTP.StatusOK})}) // Protobuf output format r.git ("/someProtoBuf", func(c *gin.Context) {reps := []int64{int64(1), int64(2)} label := "test" data := &protoexample.Test{ Label: &label, Reps: Reps,} // C. protobuf (http.statusok, data)}) r.run (":8080")}Copy the code

Gin log customization

Func main() {// Disable console color. No console color is required when writing logs to files. Gin.disableconsolecolor () // Record to file. F, _ := os.create ("gin. Log ") gin.DefaultWriter = IO. // gin.DefaultWriter = io.MultiWriter(f, os.Stdout) r := gin.Default() r.GET("/ping", func(c *gin.Context) { c.String(200, Func main() {r := gin.Default() gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers) } r.POST("/foo", func(c *gin.Context) { c.JSON(http.StatusOK, "foo") }) r.GET("/bar", func(c *gin.Context) { c.JSON(http.StatusOK, "bar") }) r.GET("/status", func(c *gin.Context) { c.JSON(http.StatusOK, "ok") }) r.Run() }Copy the code

13. HTML static rendering

Func main() {router := gin.Default() router.LoadHTMLGlob("templates/*") //router.LoadHTMLFiles("templates/template1.html", "templates/template2.html") router.GET("/index", func(c *gin.Context) { c.HTML(http.StatusOK, "index.tmpl", gin.H{ "title": "Main website", })} router.run (":8080")} templates/index.tmpl < HTML > <h1> {{.title}} </h1> </ HTML // Assignment of the same template in different directories func main() { router := gin.Default() router.LoadHTMLGlob("templates/**/*") router.GET("/posts/index", func(c *gin.Context) { c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{ "title": "Posts", }) }) router.GET("/users/index", func(c *gin.Context) { c.HTML(http.StatusOK, "users/index.tmpl", gin.H{ "title": "Users", }) }) router.Run(":8080") } templates/posts/index.tmpl {{ define "posts/index.tmpl" }} <html><h1> {{ .title }} </h1> <p>Using posts/index.tmpl</p> </html> {{ end }} templates/users/index.tmpl {{ define "users/index.tmpl" }} <html><h1> {{  .title }} </h1> <p>Using users/index.tmpl</p> </html> {{ end }}Copy the code

summary

The number of Go related Web frameworks is not small, but the frequently used ones are GIN, Beego and Iris. Considering that the implementation principle of The Web framework itself is basically the same, which is based on the encapsulation of native routing rules, this article focuses on explaining gin framework. The basic idea is to explain the function of the framework itself, the binding and acquisition of parameters in various routing scenarios, as well as some Web-related knowledge. I hope to focus on mastering the explained knowledge, and there may be related supplements according to the situation.