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
}

修改模板

deploy/goctl/1.7.1/api/handler.tpl

加入下面的代码 ③ ④ ⑤ ⑥

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

package {{.PkgName}}

import (
    {{if .HasRequest}} {{end}}
    "net/http"
    "strconv"

    "ytss_go_zero/common/errorx" // ①
    "ytss_go_zero/common/response" // ②
    {{.ImportPackages}}
    {{if .HasRequest}}"ytss_go_zero/common/validator" // ③

    "github.com/zeromicro/go-zero/rest/httpx" // ④
    {{end}}


)

{{if .HasDoc}}{{.Doc}}{{end}}
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, errorx.NewDefaultError(err.Error())) // ④  ①
            return
        }
        {{if .HasRequest}}
            // ③ validator10 验证
            if errMsg, errCode := validator.Validate(req); errCode != 0 {
                httpx.Error(w, errorx.NewCodeError(strconv.Itoa(errCode), errMsg)) // ④  ①
                return
            }
            {{end}}
        {{end}}

         l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx)
        {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}})
       if err != nil {
            httpx.Error(w, err) // ①
        } else {
            {{if .HasResp}}response.OkJson(w, "SUCCESS", resp, nil) //②{{else}}response.OkJson(w, "SUCCESS", nil, nil) //② {{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

生成模板代码

app/api/admin/internal/handler/adminUser/admin_login_handler.go

package adminUser

import (
    "net/http"
    "strconv"

    "ytss_go_zero/app/api/admin/internal/logic/adminUser"
    "ytss_go_zero/app/api/admin/internal/svc"
    "ytss_go_zero/app/api/admin/internal/types"
    "ytss_go_zero/common/errorx"   // ①
    "ytss_go_zero/common/response" // ②

    "ytss_go_zero/common/validator" // ③

    "github.com/zeromicro/go-zero/rest/httpx" // ④
)

// 管理员登录
func AdminLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        var req types.LoginReq
        if err := httpx.Parse(r, &req); err != nil {
            httpx.Error(w, errorx.NewDefaultError(err.Error())) // ④  ①
            return
        }

        // ③ validator10 验证
        if errMsg, errCode := validator.Validate(req); errCode != 0 {
            httpx.Error(w, errorx.NewCodeError(strconv.Itoa(errCode), errMsg)) // ④  ①
            return
        }

        l := adminUser.NewAdminLoginLogic(r.Context(), svcCtx)
        resp, err := l.AdminLogin(&req,r)
        if err != nil {
            httpx.Error(w, err) // ①
        } else {
            response.OkJson(w, "SUCCESS", resp, nil) //②
        }
    }
}

请求接口

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
最后编辑:海马  更新时间:2024-12-22 19:32