API 路由分组
在 go-zero 中,我们通过 api 语言来声明 HTTP 服务,然后通过 goctl 生成 HTTP 服务代码,在之前我们系统性的介绍了 API 规范。
在 HTTP 服务开发中,随着业务的发展,我们的服务接口会越来越多,生成的代码文件(handler,logic,types 文件等)也会越来越多,这时候我们需要将一些生成的代码文件按照一定维度进行文件夹聚合,以便于开发和维护。
假设我们有一个用户服务,我们有多个接口如下:
https://example.com/v1/user/loginhttps://example.com/v1/user/infohttps://example.com/v1/user/info/updatehttps://example.com/v1/user/list
https://example.com/v1/user/role/listhttps://example.com/v1/user/role/updatehttps://example.com/v1/user/role/infohttps://example.com/v1/user/role/addhttps://example.com/v1/user/role/delete
https://example.com/v1/user/class/listhttps://example.com/v1/user/class/updatehttps://example.com/v1/user/class/infohttps://example.com/v1/user/class/addhttps://example.com/v1/user/class/delete我们首先来看一下在不进行分组的情况下 api 语言的写法:
syntax = "v1"
type ( UserLoginReq{} UserInfoReq{} UserLoginResp{} UserInfoResp{} UserInfoUpdateReq{} UserInfoUpdateResp{})
type ( UserRoleReq{} UserRoleResp{} UserRoleUpdateReq{} UserRoleUpdateResp{} UserRoleAddReq{} UserRoleAddResp{} UserRoleDeleteReq{} UserRoleDeleteResp{})
type ( UserClassReq{} UserClassResp{} UserClassUpdateReq{} UserClassUpdateResp{} UserClassAddReq{} UserClassAddResp{} UserClassDeleteReq{} UserClassDeleteResp{})@server( prefix: /v1)service user-api { @handler UserLogin post /user/login (UserLoginReq) returns (UserLoginResp)
@handler UserInfo post /user/info (UserInfoReq) returns (UserInfoResp)
@handler UserInfoUpdate post /user/info/update (UserInfoUpdateReq) returns (UserInfoUpdateResp)
@handler UserList get /user/list returns ([]UserInfoResp)
@handler UserRoleList get /user/role/list returns ([]UserRoleResp)
@handler UserRoleUpdate get /user/role/update (UserRoleUpdateReq) returns (UserRoleUpdateResp)
@handler UserRoleInfo get /user/role/info (UserRoleReq) returns (UserRoleResp)
@handler UserRoleAdd get /user/role/add (UserRoleAddReq) returns (UserRoleAddResp)
@handler UserRoleDelete get /user/role/delete (UserRoleDeleteReq) returns (UserRoleDeleteResp)
@handler UserClassList get /user/class/list returns ([]UserClassResp)
@handler UserClassUpdate get /user/class/update (UserClassUpdateReq) returns (UserClassUpdateResp)
@handler UserClassInfo get /user/class/info (UserClassReq) returns (UserClassResp)
@handler UserClassAdd get /user/class/add (UserClassAddReq) returns (UserClassAddResp)
@handler UserClassDelete get /user/class/delete (UserClassDeleteReq) returns (UserClassDeleteResp)}在不分组的情况下生成的代码目录结构如下:
.├── etc│ └── user-api.yaml├── internal│ ├── config│ │ └── config.go│ ├── handler│ │ ├── routes.go│ │ ├── userclassaddhandler.go│ │ ├── userclassdeletehandler.go│ │ ├── userclassinfohandler.go│ │ ├── userclasslisthandler.go│ │ ├── userclassupdatehandler.go│ │ ├── userinfohandler.go│ │ ├── userinfoupdatehandler.go│ │ ├── userlisthandler.go│ │ ├── userloginhandler.go│ │ ├── userroleaddhandler.go│ │ ├── userroledeletehandler.go│ │ ├── userroleinfohandler.go│ │ ├── userrolelisthandler.go│ │ └── userroleupdatehandler.go│ ├── logic│ │ ├── userclassaddlogic.go│ │ ├── userclassdeletelogic.go│ │ ├── userclassinfologic.go│ │ ├── serclasslistlogic.go│ │ ├── userclassupdatelogic.go│ │ ├── userinfologic.go│ │ ├── userinfoupdatelogic.go│ │ ├── userlistlogic.go│ │ ├── userloginlogic.go│ │ ├── userroleaddlogic.go│ │ ├── userroledeletelogic.go│ │ ├── userroleinfologic.go│ │ ├── userrolelistlogic.go│ │ └── userroleupdatelogic.go│ ├── svc│ │ └── servicecontext.go│ └── types│ └── types.go├── user.api└── user.go
7 directories, 35 files由于我们没有进行分组,所以生成的代码中handler 和 logic 结构体目录下的文件是全部揉在一起的,这样的目录结构在项目中不太好管理和阅读,接下来我们按照 user,role,class 来进行分组,在 api 语言中,我们可以通过在 @server 语句块中使用 group 关键字来进行分组,分组的语法如下:
syntax = "v1"
type ( UserLoginReq {} UserInfoReq {} UserLoginResp {} UserInfoResp {} UserInfoUpdateReq {} UserInfoUpdateResp {})
type ( UserRoleReq {} UserRoleResp {} UserRoleUpdateReq {} UserRoleUpdateResp {} UserRoleAddReq {} UserRoleAddResp {} UserRoleDeleteReq {} UserRoleDeleteResp {})
type ( UserClassReq {} UserClassResp {} UserClassUpdateReq {} UserClassUpdateResp {} UserClassAddReq {} UserClassAddResp {} UserClassDeleteReq {} UserClassDeleteResp {})
@server ( prefix: /v1 group: user)service user-api { @handler UserLogin post /user/login (UserLoginReq) returns (UserLoginResp)
@handler UserInfo post /user/info (UserInfoReq) returns (UserInfoResp)
@handler UserInfoUpdate post /user/info/update (UserInfoUpdateReq) returns (UserInfoUpdateResp)
@handler UserList get /user/list returns ([]UserInfoResp)}
@server ( prefix: /v1 group: role)service user-api { @handler UserRoleList get /user/role/list returns ([]UserRoleResp)
@handler UserRoleUpdate get /user/role/update (UserRoleUpdateReq) returns (UserRoleUpdateResp)
@handler UserRoleInfo get /user/role/info (UserRoleReq) returns (UserRoleResp)
@handler UserRoleAdd get /user/role/add (UserRoleAddReq) returns (UserRoleAddResp)
@handler UserRoleDelete get /user/role/delete (UserRoleDeleteReq) returns (UserRoleDeleteResp)}
@server ( prefix: /v1 group: class)service user-api { @handler UserClassList get /user/class/list returns ([]UserClassResp)
@handler UserClassUpdate get /user/class/update (UserClassUpdateReq) returns (UserClassUpdateResp)
@handler UserClassInfo get /user/class/info (UserClassReq) returns (UserClassResp)
@handler UserClassAdd get /user/class/add (UserClassAddReq) returns (UserClassAddResp)
@handler UserClassDelete get /user/class/delete (UserClassDeleteReq) returns (UserClassDeleteResp)}我们再来看一下分组后的代码生成目录结构:
.├── etc│ └── user-api.yaml├── internal│ ├── config│ │ └── config.go│ ├── handler│ │ ├── class│ │ │ ├── userclassaddhandler.go│ │ │ ├── userclassdeletehandler.go│ │ │ ├── userclassinfohandler.go│ │ │ ├── userclasslisthandler.go│ │ │ └── userclassupdatehandler.go│ │ ├── role│ │ │ ├── userroleaddhandler.go│ │ │ ├── userroledeletehandler.go│ │ │ ├── userroleinfohandler.go│ │ │ ├── userrolelisthandler.go│ │ │ └── userroleupdatehandler.go│ │ ├── routes.go│ │ └── user│ │ ├── userinfohandler.go│ │ ├── userinfoupdatehandler.go│ │ ├── userlisthandler.go│ │ └── userloginhandler.go│ ├── logic│ │ ├── class│ │ │ ├── userclassaddlogic.go│ │ │ ├── userclassdeletelogic.go│ │ │ ├── userclassinfologic.go│ │ │ ├── userclasslistlogic.go│ │ │ └── userclassupdatelogic.go│ │ ├── role│ │ │ ├── userroleaddlogic.go│ │ │ ├── userroledeletelogic.go│ │ │ ├── userroleinfologic.go│ │ │ ├── userrolelistlogic.go│ │ │ └── userroleupdatelogic.go│ │ └── user│ │ ├── userinfologic.go│ │ ├── userinfoupdatelogic.go│ │ ├── userlistlogic.go│ │ └── userloginlogic.go│ ├── svc│ │ └── servicecontext.go│ └── types│ ├── class.go│ ├── role.go│ └── user.go└── user.go
14 directories, 36 files通过分组,我们可以很方便的将不同的业务逻辑分组到不同的目录下,这样可以很方便的管理不同的业务逻辑。
:::note 注意
通过命令行参数 --types-group 可开启 types 分组,types 分组会按照 group 名称生成不同的文件,而不是按照目录分组,生成示例如下
goctl api go --api $api --dir $output --type-grouptypes 分组需要 goctl 大于等于 1.8.3 版本
该功能处于实验性阶段,如果兼容问题请执行命令 goctl env -w GOCTL_EXPERIMENTAL=off 关闭实验性功能即可
请注意,实验功能非稳定版本,有存在调整的可能。
:::