go-zero内置验证

参考文档:
https://go-zero.dev/cn/docs/design/grammar#type%E8%AF%AD%E6%B3%95%E5%9D%97

tag定义和golang中json tag语法一样,除了json tag外,go-zero还提供了另外一些tag来实现对字段的描述, 详情见下表。

tag修饰符

常见参数校验描述

tag key 描述 有效范围 示例
optional 定义当前字段为可选参数 request json:”name,optional
options 定义当前字段的枚举值,多个以竖线|隔开 request json:”gender,options=male”
default 定义当前字段默认值 request json:”gender,default=male”
range 定义当前字段数值范围 request json:”age,range=[0:120]”

tag修饰符需要在tag value后以英文逗号,隔开

例子

type UserInfoGetRequest {
    Name   string `form:"name,optional"`
}

返回错误

error: value \"1\" for field \"name\" is not defined in options \"[li wang]\"

返回 json 格式错误需要定义错误处理,参考 错误处理 文档

返回例子:

{
    "code": 1001,
    "msg": "error: value \"1\" for field \"name\" is not defined in options \"[li wang]\""
}

第三方验证插件validator10

安装验证包

go get -u github.com/go-playground/validator/v10

新建文件 validator.go

项目根目录里新建文件 pkg/validator/validator.go

vim pkg/validator/validator.go

写入下面的内容

package validator

import (
    "fmt"
    "net/http"
    "reflect"

    "github.com/go-playground/locales/zh_Hans_CN"
    unTrans "github.com/go-playground/universal-translator"
    "github.com/go-playground/validator/v10"
    zhTrans "github.com/go-playground/validator/v10/translations/zh"
)

func Validate(data interface{}) (string, int) {
    validate := validator.New()
    uni := unTrans.New(zh_Hans_CN.New())
    trans, _ := uni.GetTranslator("zh_Hans_CN")

    err := zhTrans.RegisterDefaultTranslations(validate, trans)
    if err != nil {
        fmt.Println("err:", err)
    }
    validate.RegisterTagNameFunc(func(field reflect.StructField) string {
        label := field.Tag.Get("label")
        return label
    })

    err = validate.Struct(data)
    if err != nil {
        for _, v := range err.(validator.ValidationErrors) {
            return v.Translate(trans), http.StatusUnprocessableEntity
        }
    }
    return "", 0
}

修改模板

goctlTpl/1.4.2/api/handler.tpl

加入下面的代码 ③ ④ ⑤ ⑥

注意 ① ②处的代码,需要配合自定义模板和错误处理使用,参考 错误处理模板修改 的文档

package {{.PkgName}}

import (
    "net/http"
    "github.com/zeromicro/go-zero/rest/httpx"
    "go-zero-demo/common/response" // ①
    "go-zero-demo/pkg/validator"   // ③
    "go-zero-demo/common/errorx" // ④
    "log" // ⑤
    {{.ImportPackages}}
)

func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        {{if .HasRequest}}var req types.{{.RequestType}}
        if err := httpx.Parse(r, &req); err != nil {
            httpx.Error(w, err)
            return
        }{{end}}

        if errMsg, errCode := validator.Validate(req); errCode != 0 {
            log.Printf("request params validate failed, err: %s, params: %+v", errMsg, req)
            httpx.Error(w, errorx.NewDefaultError(errMsg))
            return
        } // ⑥

        l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
        {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
        {{if .HasResp}}response.Response(w, resp, err){{else}}response.Response(w, nil, err){{end}}// ②
    }
}

修改 user.api 加入 tag

syntax = "v1"

info(
    author: "user-api"
    date:   "2022-03-26"
    desc:   "api语法示例及语法说明"
)

import (
    "user/user_data.api"
)

type UserInfoGetRequest {
    UserId int64  `form:"userId" validate:"required,gte=0" label:"用戶id"` // ①
    Name   string `form:"name" validate:"required,gte=5" label:"姓名"` // ②
}

type UserInfoGetResponse {
    UserId   int64  `json:"userId"`
    Nickname string `json:"nickname"`
}


// service block
@server(
    group: user
    prefix: api/v1
)

service user-api{
    @doc "获取用户信息get"
    @handler userInfoGet
    get /user/info_get (UserInfoGetRequest) returns (UserInfoGetResponse)

}

生成API代码

指定生成模板API代码命令

cd user-api/api

指定生成模板
alias apigen=”goctl api go -api *.api -dir ../ –style=goZero –home=../../goctlTp

生成模板代码

user-api/internal/handler/user/userInfoGetHandler.go

package user

import (
    "github.com/zeromicro/go-zero/rest/httpx"
    "go-zero-demo/common/errorx"   //④
    "go-zero-demo/common/response" // ①
    "go-zero-demo/pkg/validator"   // ③
    "go-zero-demo/user-api/internal/logic/user"
    "go-zero-demo/user-api/internal/svc"
    "go-zero-demo/user-api/internal/types"
    "log" // ⑤
    "net/http"
)

func UserInfoGetHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req types.UserInfoGetRequest
        if err := httpx.Parse(r, &req); err != nil {
            httpx.Error(w, err)
            return
        }

        if errMsg, errCode := validator.Validate(req); errCode != 0 {
            log.Printf("request params validate failed, err: %s, params: %+v", errMsg, req)
            httpx.Error(w, errorx.NewDefaultError(errMsg))
            return
        } // ⑥

        l := user.NewUserInfoGetLogic(r.Context(), svcCtx)
        resp, err := l.UserInfoGet(&req)
        response.Response(w, resp, err) //②
    }
}

请求接口

curl -X GET http://127.0.0.1:8888/api/v1/user/info_get?userId=1&name=1

请求返回结果:

{
    "code": 1001,
    "msg": "姓名长度必须至少为5个字符"
}
作者:admin  创建时间:2022-10-30 09:24
最后编辑:admin  更新时间:2024-05-10 15:32