[系列] go-gin-api 規劃目錄和參數驗證(二)

  • 2019 年 10 月 3 日
  • 筆記

概述

首先同步下項目概況:

上篇文章分享了,使用 go modules 初始化項目,這篇文章咱們分享:

  • 規劃目錄結構
  • 模型綁定和驗證
  • 自定義驗證器
  • 制定 API 返回結構

廢話不多說,咱們開始吧。

規劃目錄結構

├─ go-gin-api  │  ├─ app  │     ├─ config           //配置文件  │        ├─ config.go  │     ├─ controller       //控制器層  │        ├─ param_bind  │        ├─ param_verify  │        ├─ ...  │     ├─ model            //資料庫ORM  │        ├─ proto  │        ├─ ...  │     ├─ repository       //資料庫操作層  │        ├─ ...  │     ├─ route            //路由  │        ├─ middleware  │        ├─ route.go  │     ├─ service          //業務層  │        ├─ ...  │     ├─ util             //工具包  │        ├─ ...  │  ├─ vendor  //依賴包  │     ├─ ...  │  ├─ go.mod  │  ├─ go.sum  │  ├─ main.go //入口文件

上面的目錄結構是我自定義的,大家也可以根據自己的習慣去定義。

controller 控制器層主要對提交過來的數據進行驗證,然後將驗證完成的數據傳遞給 service 處理。

在 gin 框架中,參數驗證有兩種:

1、模型綁定和驗證。

2、自定義驗證器。

其中目錄 param_bind,存儲的是參數綁定的數據,目錄param_verify 存儲的是自定義驗證器。

接下來,讓咱們進行簡單實現。

模型綁定和驗證

比如,有一個創建商品的介面,商品名稱不能為空。

配置路由(route.go):

ProductRouter := engine.Group("")  {      // 新增產品      ProductRouter.POST("/product", product.Add)        // 更新產品      ProductRouter.PUT("/product/:id", product.Edit)        // 刪除產品      ProductRouter.DELETE("/product/:id", product.Delete)        // 獲取產品詳情      ProductRouter.GET("/product/:id", product.Detail)  }

參數綁定(param_bind/product.go):

type ProductAdd struct {      Name string `form:"name" json:"name" binding:"required"`  }

控制器調用(controller/product.go):

if err := c.ShouldBind(&param_bind.ProductAdd{}); err != nil {      utilGin.Response(-1, err.Error(), nil)      return  }

咱們用 Postman 模擬 post 請求時,name 參數不傳或傳遞為空,會出現:

Key: 'ProductAdd.Name' Error:Field validation for 'Name' failed on the 'required' tag

這就使用到了參數設置的 binding:"required"。

那麼還能使用 binding 哪些參數,有文檔嗎?

有。Gin 使用 go-playground/validator.v8 進行驗證,相關文檔:

https://godoc.org/gopkg.in/go-playground/validator.v8

接下來,咱們實現一下自定義驗證器。

自定義驗證器

比如,有一個創建商品的介面,商品名稱不能為空並且參數名稱不能等於 admin。

類似於這種業務需求,無法 binding 現成的方法,需要我們自己寫驗證方法,才能實現。

自定義驗證方法(param_verify/product.go)

func NameValid (      v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,      field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,  ) bool {      if s, ok := field.Interface().(string); ok {          if s == "admin" {              return false          }      }      return true  }

參數綁定(param_bind/product.go):

type ProductAdd struct {      Name string `form:"name" json:"name" binding:"required,NameValid"`  }

同時還要綁定驗證器:

// 綁定驗證器  if v, ok := binding.Validator.Engine().(*validator.Validate); ok {      v.RegisterValidation("NameValid", param_verify.NameValid)  }

咱們用 Postman 模擬 post 請求時,name 參數不傳或傳遞為空,會出現:

Key: 'ProductAdd.Name' Error:Field validation for 'Name' failed on the 'required' tag

name=admin 時:

Key: 'ProductAdd.Name' Error:Field validation for 'Name' failed on the 'NameValid' tag

OK,上面兩個驗證都生效了!

上面的輸出都是在控制台,能不能返回一個 Json 結構的數據呀?

能。接下來咱們制定 API 返回結構。

制定 API 返回結構

{      "code": 1,      "msg": "",      "data": null  }

API 介面的返回的結構基本都是這三個欄位。

比如 code=1 表示成功,code=-1 表示失敗。

msg 表示提示資訊。

data 表示要返回的數據。

那麼,我們怎麼在 gin 框架中實現它,其實很簡單 基於 c.JSON() 方法進行封裝即可,直接看程式碼。

package util    import "github.com/gin-gonic/gin"    type Gin struct {      Ctx *gin.Context  }    type response struct {      Code     int         `json:"code"`      Message  string      `json:"msg"`      Data     interface{} `json:"data"`  }    func (g *Gin)Response(code int, msg string, data interface{}) {      g.Ctx.JSON(200, response{          Code    : code,          Message : msg,          Data    : data,      })      return  }

控制器調用(controller/product.go):

utilGin := util.Gin{Ctx:c}  if err := c.ShouldBind(&param_bind.ProductAdd{}); err != nil {      utilGin.Response(-1, err.Error(), nil)      return  }

咱們用 Postman 模擬 post 請求時,name 參數不傳或傳遞為空,會出現:

{      "code": -1,      "msg": "Key: 'ProductAdd.Name' Error:Field validation for 'Name' failed on the 'required' tag",      "data": null  }

name=admin 時:

{      "code": -1,      "msg": "Key: 'ProductAdd.Name' Error:Field validation for 'Name' failed on the 'NameValid' tag",      "data": null  }

OK,上面兩個驗證都生效了!

源碼地址

https://github.com/xinliangnote/go-gin-api

go-gin-api 系列文章

Tags: