go-zero 完美对接 validator(接口之美)

前言

go-zero 社区中,常常有人问:go-zero 支持 go-playground/validator 吗?许多人在看到 go-zerogo.mod 文件中并没有引入 go-playground/validator 后,会以为 go-zero 不支持使用该库。事实上,这里恰恰能够体现 Go 接口设计的强大与优雅。

实际上,在两年前我就已经通过接口扩展的方式支持了 go-playground/validator,而且你可以轻松地将任何三方 validator 集成进你的项目。下面通过一个示例来展示具体实现,同时解析这种设计背后的原理。

示例演示

1. 创建项目

使用 goctl 创建一个最简单的项目:

$ goctl api new echo

2. 添加字段校验规则

打开 echo.api 文件,修改 Request 的字段,增加 validate 标签:

syntax = "v1"

type Request {
    Name string `path:"name" validate:"min=8"`
}

type Response {
    Message string `json:"message"`
}

service echo-api {
    @handler EchoHandler
    get /from/:name (Request) returns (Response)
}

这里的 validate:"min=8" 表示 Name 字段的长度至少为 8。

3. 实现验证逻辑

internal/types 下新建文件 validate.go,实现校验逻辑:

package types

import "github.com/go-playground/validator/v10"

var validate = validator.New()

func (r *Request) Validate() error {
    return validate.Struct(r)
}

4. 安装依赖

在项目根目录下运行 go mod tidy 获取 go-playground/validator 依赖包。

5. 启动服务

$ go run echo.go
Starting server at 0.0.0.0:8888...

6. 验证效果

测试未通过验证的请求:

$ curl -i "http://localhost:8888/from/a"
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
...
Key: 'Request.Name' Error:Field validation for 'Name' failed on the 'min' tag

测试通过验证的请求:

$ curl -i "http://localhost:8888/from/longenough"
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
...
null

看两次返回的 status code 对比,一个 400,一个 200bodynull 因为我们没有给返回内容。

我来总结一下项目中要使用 go-playground/validator 的具体步骤:

  1. 在需要验证的字段中增加 validate 指令

  2. internal/types 下面新建 validate.go 文件,并给对应请求类型加上 Validate 方法

  3. goctl 重新生成 internal/types

原理解析

rest/httpx/requests.go,支持的玄机就在第一行判断是否实现了 validatioin/Validator 接口,只要实现了,就会自动调用,这就是为啥我们只要加了 func (r *Request) Validate() error,就会自动验证 Request 对象了。

if valid, ok := v.(validation.Validator); ok {
    return valid.Validate()
} else if val := validator.Load(); val != nil {
    return val.(Validator).Validate(r, v)
}

另外,你可以看到我还支持了自己设置 Validator,可以通过 httpx.SetValidator(...) 来设置,这个给你传入了 r *http.Request 和解析后的对象,如下:

// Validator defines the interface for validating the request.
type Validator interface {
    // Validate validates the request and parsed data.
    Validate(r *http.Request, data any) error
}

通过这种方式, 你可以轻松接入不同的三方 validator 或实现自定义校验逻辑。

总结

从这个示例可以看出,Go 接口设计的优雅性让我们在不直接引入具体三方库的情况下实现了高扩展性。

类似的设计思路在 Go 标准库中比比皆是,例如 io.Readerio.Writer 接口的广泛应用。

go-zero 的这种设计思路不仅方便了用户,也提高了框架的灵活性和适应性。希望你通过这个示例能够更深入地理解 Go 的接口设计哲学!

项目地址

github.com/zeromicro/go-zero

欢迎使用 go-zerostar 支持我们!

本作品采用《CC 协议》,转载必须注明作者和本文链接
kevwan
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
go-zero作者 @ 某互联网公司
文章
98
粉丝
623
喜欢
630
收藏
613
排名:155
访问:6.4 万
私信
所有博文
社区赞助商