Go-Zero定义API实战:探索API语法规范与最佳实践(五)
前言
上一篇文章带你实现了Go-Zero模板定制化,本文将继续分享如何使用GO-Zero进行业务开发。
通过编写API层,我们能够对外进行接口的暴露,因此学习规范的API层编写姿势是很重要的。
通过本文的分享,你将能够学习到Go-Zero的API语法规范,以及学会实际上手使用。
概述
下文所说的是 api
是 go-zero 自研的领域特性语言(下文称 api 语言 或 api 描述语言),旨在实现人性化的基础描述语言,作为生成 HTTP 服务最基本的描述语言。
api 领域特性语言包含语法版本、info 块、结构体声明、服务描述等几大块语法组成,其中结构体和 Golang 结构体 语法几乎一样,只是移除了 struct
关键字。
实战前准备
首先需要你在本地安装goctl、go-zero
,下载教学和地址点击这里[2],按照教程操作即可,非常简单。
下面按顺序和我操作吧,对使用模板快速生成API层不清楚的同学务必先看我前篇文章:Go-Zero goctl实战[3]
这里我假设你已经创建好了一个API服务的demo,且目录结构长这样:
学习API语法
对于Go语言开发者来说,Go-Zero的API语法学习和理解成本极低,我们可以很轻松的学会API语法。下面我会为大家介绍重点需要掌握的语法。更详细的语法规范,可以参考官网:API 规范 | go-zero Documentation[4]
生成API文件
cd demo
goctl api go -api demo.api -dir . -style gozero
基础的API文件
ID标识符
golang中的预定义类型、常量、函数,以及关键字在api里面同样适用
预定义
//预定义类型:
any bool byte comparable
complex64 complex128 error float32 float64
int int8 int16 int32 int64 rune string
uint uint8 uint16 uint32 uint64 uintptr
//预定义常量:
true false iota
//零值:
nil
//预定义函数:
append cap close complex copy delete imag len
make new panic print println real recover
关键字
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
tip:需要注意的是 goctl api不支持any类型!!!
类型声明
规则
类型声明必须以 type
开头不需要声明 struct
关键字不支持嵌套结构体声明 不支持别名
示例
type StructureExample {
// 基本数据类型示例
BaseInt int `json:"base_int"`
BaseBool bool `json:"base_bool"`
BaseString string `json:"base_string"`
BaseByte byte `json:"base_byte"`
BaseFloat32 float32 `json:"base_float32"`
BaseFloat64 float64 `json:"base_float64"`
// 切片示例
BaseIntSlice []int `json:"base_int_slice"`
BaseBoolSlice []bool `json:"base_bool_slice"`
BaseStringSlice []string `json:"base_string_slice"`
BaseByteSlice []byte `json:"base_byte_slice"`
BaseFloat32Slice []float32 `json:"base_float32_slice"`
BaseFloat64Slice []float64 `json:"base_float64_slice"`
// map 示例
BaseMapIntString map[int]string `json:"base_map_int_string"`
BaseMapStringInt map[string]int `json:"base_map_string_int"`
BaseMapStringStruct map[string]*StructureExample `json:"base_map_string_struct"`
BaseMapStringIntArray map[string][]int `json:"base_map_string_int_array"`
// 匿名示例
*Base
// 指针示例
Base4 *Base `json:"base4"`
// 新的特性( goctl >= 1.5.1 版本支持 )
// 标签忽略示例
TagOmit string
}
路由前缀
我们可以通过prefix关键字区分路由组
接着再使用goctl api生成代码以及swagger,将swagger导入apifox查看路由前缀,可以看见就增添了前缀/demo。
不知道怎么生成api代码的同学可以看我往期的gozero实战分享——go-zero goctl实战[5]
服务分组
当我们的业务体量上来后,服务接口也会越来越多,生成的代码文件(handler、logic文件等)也会越来越多。这时候我们就需要对不同的接口按一定的分组进行区分,用文件夹进行隔离,以便于开发和维护。
分组前的目录结构是这样的
我们先将生成的handler和logic文件删除。 只需要在@server语句块里面添加关键字group就能进行分组。分组后的结构如下图所示。
JWT校验
接下来我们再来看一下api文件中怎么开启jwt认证 在配置文件demo-api.yaml中添加jwt配置
在config文件中添加一个JWT认证需要的密钥和过期时间配置
JwtAuth struct { // JWT 认证需要的密钥和过期时间配置
AccessSecret string
AccessExpire int64
}
使用方法也很简单,我们在@service语句块中添加jwt关键字,使用Auth即可开启jwt。
通过测试请求我们可以看见返回401没有权限,说明jwt校验生效了
路由规则
路由必须以 /
开头 2. 路由节点必须以/
分隔路由节点中可以包含 :
,但是:
必须是路由节点的第一个字符,:
后面的节点值必须要在结请求体中有path
tag 声明,用于接收路由参数,详细规则可参考 路由参数[6]。4. 路由节点可以包含字母、数字(goctl 1.5.1
支持,可参考 新版 API 解析器使用[7])、下划线、中划线
参数规则
接收规则 | 说明 | 生效范围 | 示例 |
---|---|---|---|
json | json 序列化 | 请求体&响应体 | json:"foo" |
path | 路由参数 | 请求体 | path:"id" |
form | post 请求的表单(支持 content-type 为 form-data 和 x-www-form-urlencoded ) 参数请求接收标识,get 请求的 query 参数接收标识 | 请求体 | form:"name" |
header | http 请求体接收标识 | 请求体 | header:"Content-Length" |
中间件声明
想要使用中间件,可以在@server语句块中使用关键字middleware生成一个中间件模板。 TIP:需要注意的是中间件首字母必须大写,否则无法被其他包导入。
在svc包的servicecontext.go中注册中间件
生成的中间件代码如下
API Import
当我们的业务体量上来后,api文件可能会越来越大,又或者我们有一些公共结构体。如果我们都写在同一个api文件中,那么api文件将会变得非常巨大,不易阅读和维护,这时候就需要拆解api文件,通过import来导入。
syntax
版本信息,import中的版本信息必须与被import的api版本信息一样。 规范写法
syntax = "v1"
我们创建一个新的文件demo1.api,并且将分组写到这个api文件下。 因为我们的请求体和响应体是公共结构体,都写在demo.api下面了,我们通过import "demo.api"就能导入demo.api。
完整的api文件模板
syntax = "v1"
type Request {
Name string `path:"name,options=you|me"`
}
type Response {
Message string `json:"message"`
}
@server (
prefix :/demo
group: demo_api
jwt: JwtAuth
middleware: Demo_middleware
)
// 分组1的服务
service demo-api {
@handler DemoHandler
post /from (Request) returns (Response)
}
// 分组2的服务
@server (
prefix :/demo1
group: demo_api1
)
service demo-api {
@handler DemoHandler1
get /from/:name(Request) returns (Response)
}
总结
这篇文章详细介绍了如何使用Go-Zero进行API的定义,并进行了实际演示。希望对你有帮助。
我将继续更新Go-Zero系列文章,如果你对Go语言或者微服务感兴趣,欢迎关注我,也欢迎直接私信我。
Go-Zero模板定制化: https://juejin.cn/post/7352322041850331162
[2]点击这里: https://link.juejin.cn?target=https%3A%2F%2Fgo-zero.dev%2Fdocs%2Ftasks%2Finstallation%2Fgoctl
[3]Go-Zero goctl实战: https://juejin.cn/post/7352322041850331162
[4]API 规范 | go-zero Documentation: https://link.juejin.cn?target=https%3A%2F%2Fgo-zero.dev%2Fdocs%2Ftutorials%23%E8%AF%AD%E6%B3%95%E6%A0%87%E8%AE%B0%E7%AC%A6%E5%8F%B7
[5]gozero实战分享——go-zero goctl实战: https://juejin.cn/post/7352322041850331162
[6]路由参数: https://link.juejin.cn?target=https%3A%2F%2Fgo-zero.dev%2Fdocs%2Ftutorials%2Fapi%2Fparameter
[7]新版 API 解析器使用: https://link.juejin.cn?target=https%3A%2F%2Fgo-zero.dev%2Fdocs%2Ftutorials%2Fapi%2Ffaq%231-%E6%80%8E%E4%B9%88%E4%BD%93%E9%AA%8C%E6%96%B0%E7%9A%84-api-%E7%89%B9%E6%80%A7
gozero&微服务 交流群
对微服务或者go-zero感兴趣的朋友们可以加我微信:wangzhongyang1993,备注:微服务。