[系列] - go-gin-api 规划目录和参数验证(二)

訢亮 · · 1251 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

概述

首先同步下项目概况:

上篇文章分享了,使用 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 进行验证,相关文档:

godoc.org/gopkg.in/go…

接下来,咱们实现一下自定义验证器。

自定义验证器

比如,有一个创建商品的接口,商品名称不能为空并且参数名称不能等于 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,上面两个验证都生效了!

源码地址

github.com/xinliangnot…

go-gin-api 系列文章


有疑问加站长微信联系(非本文作者)

本文来自:掘金

感谢作者:訢亮

查看原文:[系列] - go-gin-api 规划目录和参数验证(二)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1251 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传