gin

发布时间 2023-10-30 16:26:30作者: PEAR2020

1.quick start 

package main

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

func main() {
    r := gin.Default()
    //default: router with logger and recovery(crash-free) middleware
    // recovery: handle "panic"
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    r.Run(":8083") // listen and serve on 0.0.0.0:8080
}

2. restful

package main

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

func main() {
    // 使用默认中间件创建一个gin路由器
    // logger and recovery (crash-free) 中间件
    router := gin.Default()

    //router.GET("/someGet", getting)
    //router.POST("/somePost", posting)
    //router.PUT("/somePut", putting)
    //router.DELETE("/someDelete", deleting)
    //router.PATCH("/somePatch", patching)
    //router.HEAD("/someHead", head)
    //router.OPTIONS("/someOptions", options)

    // 默认启动的是 8080端口,也可以自己定义启动端口
    router.Run()
    // router.Run(":3000") for a hard coded port
}

3. router.Group 路由分组

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func goodlist(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "name": "123",
    })
}

func main() {

    router := gin.Default()

    group := router.Group("/goods")

    {
        group.GET("/list", goodlist)
        group.POST("/add", goodlist)
    }
    router.Run(":8083")

}

4. variables in URL

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

type Person struct {
    ID   string `uri:"id" binding:"required,uuid"`
    Name string `uri:"name" binding:"required"`
}

func goodlist(ctx *gin.Context) {
    ctx.JSON(http.StatusOK, gin.H{
        "name": ctx.Param("id"),
    })
}

func main() {

    router := gin.Default()

    group := router.Group("/goods")

    {
        //group.GET("/list", goodlist) 不能和下面的同时出现。怎么解决?
        group.GET("/:id", goodlist)
        // *: show the path
        group.GET("/:id/*action", func(ctx *gin.Context) {
            ctx.JSON(http.StatusOK, gin.H{
                "action": ctx.Param("action"),
            })
        })
        // add constrains to url
        group.GET("/:id/:name", func(c *gin.Context) {
            var person Person
            if err := c.ShouldBindUri(&person); err != nil {
                c.JSON(http.StatusNotFound, gin.H{"msg": err})
                return
            }
            c.JSON(http.StatusOK, gin.H{"name": person.Name, "uuid": person.ID})
        })

    }
    router.Run(":8083")

}

5. params from GET POST

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
)

func main() {
    router := gin.Default()
    router.GET("/welcome", func(ctx *gin.Context) {
        fstName := ctx.DefaultQuery("name", "bobby")
        age := ctx.DefaultQuery("age", "12")
        ctx.JSON(http.StatusOK, gin.H{
            "name": fstName,
            "age":  age,
        })
    })
    router.POST("/post", func(ctx *gin.Context) {
        fstName := ctx.DefaultPostForm("name", "bobby")
        age := ctx.DefaultPostForm("age", "12")
        ctx.JSON(http.StatusOK, gin.H{
            "name": fstName,
            "age":  age,
        })
    })
    // url + param; body + param
    router.POST("/getpost", func(ctx *gin.Context) {
        gname := ctx.Query("gname")
        gage := ctx.DefaultQuery("gage", "12")
        fstName := ctx.PostForm("name")
        age := ctx.DefaultPostForm("age", "12")
        ctx.JSON(http.StatusOK, gin.H{
            "name":  fstName,
            "age":   age,
            "gname": gname,
            "gage":  gage,
        })
    })
    router.Run(":8083")
}

6. output: JSON/protobuf/pure JSON

package main

import (
    "net/http"
    "github.com/gin-gonic/gin"
    "GoProjects/gin_start/ch05/proto"
)

func main() {
    router := gin.Default()
    router.GET("/moreJSON", func(c *gin.Context) {
        // You also can use a struct
        var msg struct {
            Name    string `json:"user"`
            Message string
            Number  int
        }
        msg.Name = "Lena"
        msg.Message = "hey"
        msg.Number = 123
        // Note that msg.Name becomes "user" in the JSON
        // Will output  :   {"user": "Lena", "Message": "hey", "Number": 123}
        c.JSON(http.StatusOK, msg)
    })
    router.GET("/moreProtobuf", func(c *gin.Context) {
        courses := []string{"python", "django", "go"}
        // The specific definition of protobuf is written in the testdata/protoexample file.
        data := &proto.Teacher{
            Name:   "bobby",
            Course: courses,
        }
        c.ProtoBuf(http.StatusOK, data)
    })
    router.Run(":8083")
}

7.  vaidator + error 注册翻译器

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "github.com/gin-gonic/gin/binding"
    "github.com/go-playground/locales/en"
    "github.com/go-playground/locales/zh"
    ut "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    enTranslations "github.com/go-playground/validator/v10/translations/en"
    zhTranslations "github.com/go-playground/validator/v10/translations/zh"
    "net/http"
)

// 定义一个全局翻译器T
var trans ut.Translator

// InitTrans 初始化翻译器
func InitTrans(locale string) (err error) {
    // 修改gin框架中的Validator引擎属性,实现自定制
    if v, ok := binding.Validator.Engine().(*validator.Validate); ok {

        zhT := zh.New() // 中文翻译器
        enT := en.New() // 英文翻译器

        // 第一个参数是备用(fallback)的语言环境
        // 后面的参数是应该支持的语言环境(支持多个)
        // uni := ut.New(zhT, zhT) 也是可以的
        uni := ut.New(enT, zhT, enT)

        // locale 通常取决于 http 请求头的 'Accept-Language'
        var ok bool
        // 也可以使用 uni.FindTranslator(...) 传入多个locale进行查找
        trans, ok = uni.GetTranslator(locale)
        if !ok {
            return fmt.Errorf("uni.GetTranslator(%s) failed", locale)
        }

        // 注册翻译器
        switch locale {
        case "en":
            err = enTranslations.RegisterDefaultTranslations(v, trans)
        case "zh":
            err = zhTranslations.RegisterDefaultTranslations(v, trans)
        default:
            err = enTranslations.RegisterDefaultTranslations(v, trans)
        }
        return
    }
    return
}

// 绑定为json
type Login struct {
    User     string `form:"user" json:"user" xml:"user"  binding:"required,m=3,max=10"`
    Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
type SignUpParam struct {
    Age        uint8  `json:"age" binding:"gte=1,lte=130"`
    Name       string `json:"name" binding:"required"`
    Email      string `json:"email" binding:"required,email"`
    Password   string `json:"password" binding:"required"`
    RePassword string `json:"re_password" binding:"required,eqfield=Password"`
}

func main() {
    if err := InitTrans("en"); err != nil {
        fmt.Printf("init trans failed, err:%v\n", err)
        return
    }
    router := gin.Default()
    // Example for binding JSON ({"user": "manu", "password": "123"})
    router.POST("/loginJSON", func(c *gin.Context) {
        var json Login
        if err := c.ShouldBindJSON(&json); err != nil {
            c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
            return
        }

        if json.User != "manu" || json.Password != "123" {
            c.JSON(http.StatusUnauthorized, gin.H{"status": "unauthorized"})
            return
        }

        c.JSON(http.StatusOK, gin.H{"status": "you are logged in"})
    })
    router.POST("/signup", func(c *gin.Context) {
        var u SignUpParam
        if err := c.ShouldBind(&u); err != nil {
            errs, ok := err.(validator.ValidationErrors)
            if !ok {
                // 非validator.ValidationErrors类型错误直接返回
                c.JSON(http.StatusOK, gin.H{
                    "msg": err.Error(),
                })
                return
            }
            // validator.ValidationErrors类型错误则进行翻译
            c.JSON(http.StatusOK, gin.H{
                "msg": errs.Translate(trans),
            })
            return
        }
        // 保存入库等业务逻辑代码...

        c.JSON(http.StatusOK, "success")
    })
    router.Run(":8083")
}

result:

{
    "msg": {
        "SignUpParam.Age": "Age must be 1 or greater",
        "SignUpParam.Email": "Email is a required field",
        "SignUpParam.Name": "Name is a required field",
        "SignUpParam.Password": "Password is a required field",
        "SignUpParam.RePassword": "RePassword is a required field"
    }
}