go-zero 完美对接 validator(接口之美)
前言
在 go-zero
社区中,常常有人问:go-zero
支持 go-playground/validator
吗?许多人在看到 go-zero
的 go.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
,一个 200
,body
是 null
因为我们没有给返回内容。
我来总结一下项目中要使用 go-playground/validator
的具体步骤:
在需要验证的字段中增加
validate
指令在
internal/types
下面新建validate.go
文件,并给对应请求类型加上Validate
方法用
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.Reader
和 io.Writer
接口的广泛应用。
go-zero
的这种设计思路不仅方便了用户,也提高了框架的灵活性和适应性。希望你通过这个示例能够更深入地理解 Go
的接口设计哲学!
项目地址
欢迎使用 go-zero
并 star 支持我们!
本作品采用《CC 协议》,转载必须注明作者和本文链接