go-zero 获取参数 yaml 配置文件 参数校验 validate

go-zero API参数定义 + 参数校验

本节目标:掌握 goctl api 里三种最常用入参标签:pathqueryjson,以及参数校验。 对应 Gin 里的 path、form、json、binding,对比记忆。

一、三种参数标签总览

标签 含义 对应位置 适用请求
path:"name" 路径参数 /user/:id GET
form:"name" URL查询参数 /user?id=1&name=wang GET
json:"name" JSON请求体 {"name":"xxx"} POST/PUT

规则:

  1. 一个结构体可以同时包含 path + query(GET接口常用)
  2. POST接口一般只用 json,接收body
  3. go-zero 自动根据 http 方法,自动解析对应位置参数

二、示例:同时带 path 和 query 参数(GET接口)

修改你的 user.api 文件,新增一个接口GetUserDetail

less 复制代码
type UserReq {
    Id   int    `path:"id"`
    Name string `form:"name"`
}
type UserResp {
    Name string
    Age  int
}

@server(
    prefix: /api
)
service user-api {
    @handler GetUser
    get /user/:id (UserReq) returns (UserResp)

    // 新增:获取用户详情,path参数id + query参数name
    @handler GetUserDetail
    get /user/detail/:id (UserReq) returns (UserResp)
}

保存api,执行代码生成:

bash 复制代码
goctl api go -api user.api -dir .

⚠️ 生成会更新handler、types,不会覆盖logic

写 logic 业务代码

打开 internal/logic/getuserdetaillogic.go

go 复制代码
func (l *GetUserDetailLogic) GetUserDetail(req *types.UserReq) (*types.UserResp, error) {
	// req.Id 来自路径 :id
	// req.Name 来自url ?name=xxx
	return &types.UserResp{
		Name: fmt.Sprintf("用户:%s,编号%d", req.Name, req.Id),
		Age:  20,
	}, nil
}

重启服务测试:

arduino 复制代码
curl "http://127.0.0.1:8888/api/user/detail/100?name=wang"

返回:

json 复制代码
{"name":"用户:wang,编号100","age":20}

三、POST接口,JSON请求体(json标签)

继续在 user.api 增加创建用户接口

go 复制代码
type CreateUserReq {
    Username string `json:"username"`
    Password string `json:"password"`
}
type CreateUserResp {
    Uid int64 `json:"uid"`
}

// 放在service {}里面
@handler CreateUser
post /user/create (CreateUserReq) returns (CreateUserResp)

再次执行生成:

bash 复制代码
goctl api go -api user.api -dir .

打开 internal/logic/createuserlogic.go

go 复制代码
func (l *CreateUserLogic) CreateUser(req *types.CreateUserReq) (*types.CreateUserResp, error) {
    // req.Username、req.Password 从json body中解析
	l.Infof("收到创建用户请求,username=%s", req.Username)
	return &types.CreateUserResp{
		Uid: 10001,
	}, nil
}

测试POST请求:

json 复制代码
curl -X POST -H "Content-Type: application/json" -d '{"username":"zhangsan","password":"123456"}' [http://127.0.0.1:8888/api/user/create](http://127.0.0.1:8888/api/user/create)

返回:

json 复制代码
{"uid":10001}

四、参数校验(重点,对应Gin binding)

go-zero 内置基于 validator 的校验,在tag增加 validate:"规则"

支持的常用规则:

  • required 必填
  • min=6 最小长度
  • email 邮箱格式
  • gt=0 数字大于0

修改CreateUserReq加上校验:

lua 复制代码
type CreateUserReq {
    Username string `json:"username" validate:"required,min=2"`
    Password string `json:"password" validate:"required,min=6"`
}

✅含义:username必填,最少2个字符;password必填,最少6位。

重新执行生成命令。

go-zero 会自动在校验失败时,直接返回400错误,不需要手写if判断!

测试非法请求,密码太短:

json 复制代码
curl -X POST -H "Content-Type: application/json" -d '{"username":"z","password":"123"}' [http://127.0.0.1:8888/api/user/create](http://127.0.0.1:8888/api/user/create)

服务直接返回校验错误,不需要业务代码判断。

yaml

vbnet 复制代码
Name: user-api
Host: 0.0.0.0
Port: 8888

Author: long
Version: v1.0.0

internal/config/config.go 配置对应的字段

go 复制代码
type Config struct {
	rest.RestConf
	Author  string
	Version string
}

rest.RestConf:go-zero 内置的 http 服务配置,包含 Name、Host、Port

internal/svc/servicecontext.go会自动的加载配置参数

读取配置信息

go 复制代码
func (l *GetUserLogic) GetUser(req *types.UserReq) (resp *types.UserResp, err error) {
	// todo: add your logic here and delete this line
	author := l.svcCtx.Config.Author
	version := l.svcCtx.Config.Version
	userIdStr := strconv.Itoa(req.Id)
	return &types.UserResp{
		Name: "用户" + userIdStr + " " + author + " " + version,
	}, nil
}

参数校验 validate

太棒了🎉! 原理一句话记住:

不写yaml tag时,go-zero使用go的yaml库自动忽略大小写匹配;写了tag之后,就严格完全匹配(大小写敏感)。 所以你yaml写Author,结构体字段Author,去掉tag直接就能映射上,省去大小写坑。

小结这个知识点(面试会问)

  1. 结构体字段首字母必须大写,否则私有,反射读不到;
  2. yaml:"xxx" tag:严格匹配,大小写敏感;
  3. 没有tag:自动按字段名忽略大小写映射;
  4. yaml缩进必须是空格,禁止tab,层级错直接读不到值。

现在访问接口:

ruby 复制代码
curl [http://127.0.0.1:8888/api/user/100](http://127.0.0.1:8888/api/user/100)

你应该能拿到拼接好的 Name:用户100 long v1.0.0

第五节:go-zero 参数校验 validate(基于validator)

给请求结构体增加校验规则,客户端传非法参数,框架自动拦截,不用手写if判断

go 复制代码
go get github.com/go-playground/validator/v10
go mod tidy

1. 语法写在 api 文件里(goctl生成)

打开 user.api

python 复制代码
type UserReq {
    Id int `path:"id" validate:"required,gt=0"`
}

@server(
    prefix: /api
)
service user-api {
    @get("/user/:id")
    GetUser(UserReq) returns (UserResp)
}
  • validate:"required":必填,不能空
  • gt=0:greater than,必须大于0

执行goctl重新生成代码(只要api改了,都要重新生成handler/types

bash 复制代码
goctl api go -api user.api -dir .

生成后,types.go里的结构体自动带上validate标签。

2. 常用校验tag

ini 复制代码
required  必填
gt=10     数字 > 10
gte=10    >=10
lt=10     <10
lte=10    <=10
email     邮箱格式
min=3     字符串最小长度
max=10    字符串最大长度
oneof=male female 只能是male或者female

3. 自动校验时机

go-zero的rest handler在进入你的logic之前自动执行校验 。 参数不合法,直接返回错误信息,logic代码根本不会执行

测试:访问 /api/user/-1 Id=-1,不满足gt=0,直接返回400错误。

4. 自定义错误提示(可选)

lua 复制代码
type UserReq {
    Id int `path:"id" validate:"required,gt=0" msg:"id必须大于0"`
}

动手任务

  1. 修改user.api,给UserReq加上validate校验 validate:"required,gt=0"
  2. goctl重新生成代码
  3. 测试正常:/api/user/100
  4. 测试非法:/api/user/-5,看是否直接返回参数错误

做完测试成功回复:好了,下一节,我们学习MySQL模型CRUD。

要不要我顺带讲一下,validate底层原理(go-zero怎么在进入logic前自动校验)?

相关推荐
西瓜太郎123417 小时前
外层模型卡片与分组详情成功率不一致,应该怎么排查?
前端·typescript·go·软件工程·react
天天喝旺仔17 小时前
Go 并发编程:Goroutine 与 Channel 实战
云原生·性能优化·架构·go
妙码生花1 天前
利用AI从零学Go并完成实战项目,完工总结:目录结构
前端·后端·go
妙码生花1 天前
利用AI从零学Go并完成实战项目,完工总结:商业级开源产品定位和核心特性介绍
前端·后端·go
名字还没想好☜1 天前
Go 用 json.Decoder 流式解析大 JSON:边读边处理不爆内存
开发语言·后端·golang·go·json
小满zs2 天前
Go语言第十二章(通道)
后端·go
a187927218312 天前
【算法】链表(二):链表上的双指针——变速、异链与定距,和一份路程账本
数据结构·算法·leetcode·链表·go·指针·环形链表
江湖十年2 天前
Go 虚荣域名详解:我用 go get -x 抓了个包,终于看清了 Go 工具链“对暗号”的全过程
后端·面试·go