服务分组
概述
在 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/listhttps://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/deletehttps://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 UserLoginpost /user/login (UserLoginReq) returns (UserLoginResp)@handler UserInfopost /user/info (UserInfoReq) returns (UserInfoResp)@handler UserInfoUpdatepost /user/info/update (UserInfoUpdateReq) returns (UserInfoUpdateResp)@handler UserListget /user/list returns ([]UserInfoResp)@handler UserRoleListget /user/role/list returns ([]UserRoleResp)@handler UserRoleUpdateget /user/role/update (UserRoleUpdateReq) returns (UserRoleUpdateResp)@handler UserRoleInfoget /user/role/info (UserRoleReq) returns (UserRoleResp)@handler UserRoleAddget /user/role/add (UserRoleAddReq) returns (UserRoleAddResp)@handler UserRoleDeleteget /user/role/delete (UserRoleDeleteReq) returns (UserRoleDeleteResp)@handler UserClassListget /user/class/list returns ([]UserClassResp)@handler UserClassUpdateget /user/class/update (UserClassUpdateReq) returns (UserClassUpdateResp)@handler UserClassInfoget /user/class/info (UserClassReq) returns (UserClassResp)@handler UserClassAddget /user/class/add (UserClassAddReq) returns (UserClassAddResp)@handler UserClassDeleteget /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.go7 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: /v1group: user)service user-api {@handler UserLoginpost /user/login (UserLoginReq) returns (UserLoginResp)@handler UserInfopost /user/info (UserInfoReq) returns (UserInfoResp)@handler UserInfoUpdatepost /user/info/update (UserInfoUpdateReq) returns (UserInfoUpdateResp)@handler UserListget /user/list returns ([]UserInfoResp)}@server (prefix: /v1group: role)service user-api {@handler UserRoleListget /user/role/list returns ([]UserRoleResp)@handler UserRoleUpdateget /user/role/update (UserRoleUpdateReq) returns (UserRoleUpdateResp)@handler UserRoleInfoget /user/role/info (UserRoleReq) returns (UserRoleResp)@handler UserRoleAddget /user/role/add (UserRoleAddReq) returns (UserRoleAddResp)@handler UserRoleDeleteget /user/role/delete (UserRoleDeleteReq) returns (UserRoleDeleteResp)}@server (prefix: /v1group: class)service user-api {@handler UserClassListget /user/class/list returns ([]UserClassResp)@handler UserClassUpdateget /user/class/update (UserClassUpdateReq) returns (UserClassUpdateResp)@handler UserClassInfoget /user/class/info (UserClassReq) returns (UserClassResp)@handler UserClassAddget /user/class/add (UserClassAddReq) returns (UserClassAddResp)@handler UserClassDeleteget /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.go14 directories, 36 files
通过分组,我们可以很方便的将不同的业务逻辑分组到不同的目录下,这样可以很方便的管理不同的业务逻辑。
注意
通过命令行参数 --types-group 可开启 types 分组,types 分组会按照 group 名称生成不同的文件,而不是按照目录分组,生成示例如下
goctl api go --api $api --dir $output --type-group
types 分组需要 goctl 大于等于 1.8.3 版本 该功能处于实验性阶段,如果兼容问题请执行命令 goctl env -w GOCTL_EXPERIMENTAL=off 关闭实验性功能即可 请注意,实验功能非稳定版本,有存在调整的可能。