目录
前言
在学习go-zero的过程中,我简单记录了http、rpc服务的代码生成方法,以及mysql和mongodb的数据库模型代码生成步骤,作为备忘录使用。初学,如有不妥之处,感谢指正。
包结构
这部分借用官网内容,介绍了生成代码的包结构。
工程维度
.
├── consumer
├── go.mod
├── internal
│ └── model
├── job
├── pkg
├── restful
├── script
└── service
- consumer: 队列消费服务
- internal: 工程内部可访问的公共模块
- job: cron job 服务
- pkg: 工程外部可访问的公共模块
- restful:HTTP 服务目录,下存放以服务为维度的微服务
- script:脚本服务目录,下存放以脚本为维度的服务
- service:gRPC 服务目录,下存放以服务为维度的微服务
服务维度
example
├── etc
│ └── example.yaml
├── main.go
└── internal
├── config
│ └── config.go
├── handler
│ ├── xxxhandler.go
│ └── xxxhandler.go
├── logic
│ └── xxxlogic.go
├── svc
│ └── servicecontext.go
└── types
└── types.go
- example:单个服务目录,一般是某微服务名称
- etc:静态配置文件目录
- main.go:程序启动入口文件
- internal:单个服务内部文件,其可见范围仅限当前服务
- config:静态配置文件对应的结构体声明目录
- handler:handler 目录,可选,一般 http 服务会有这一层做路由管理,
handler为固定后缀 - logic:业务目录,所有业务编码文件都存放在这个目录下面,
logic为固定后缀 - svc:依赖注入目录,所有 logic 层需要用到的依赖都要在这里进行显式注入
- types:结构体存放目录
Http服务代码生成
api描述http服务,编写好api文件后,使用命令goctl api go --api xx.api --dir . 在指定目录生成文件。
注意修改api文件重新生成后记得检查一下是否代码逻辑成功修改了,有些修改不会被检测到,此时要删掉文件重新生成。
api指令常见的用法如下表所示,更详细的用法可以参考 https://go-zero.dev/docs/tutorials/cli/api 。前端代码生成似乎略微有些地方不兼容。
| 功能 | 命令 | 说明 |
|---|---|---|
| 生成 Go 后端服务 | goctl api go --api <api_file> --dir <output_dir> --style <style> |
根据 .api 文件生成完整的 HTTP 后端服务代码。 --api:输入 .api 文件路径;--dir:代码输出目录;--style:文件命名风格(gozero/goZero/go_zero)。 |
| 创建 .api 模板文件 | goctl api new --style <style> <service_name> |
创建包含示例语法的 .api 模板文件。 <service_name>:生成 service_name.api 文件; --style:文件命名风格。 |
| 格式化 .api 文件 | goctl api format --dir <api_file_or_dir> |
自动格式化指定的 .api 文件或目录。 |
| 校验 .api 文件 | goctl api validate --api <api_file> |
语法检查(不生成代码),适合在提交前或 CI 流程中使用。 |
| 生成 TS/JS 前端代码 | goctl api ts --api <api_file> --dir <output_dir> |
生成前端调用代码(请求函数 + 类型定义)。 --api:api文件;--dir:输出文件夹;下面所有客户端代码同理。 |
| 生成 Dart 客户端代码 | goctl api dart --api <api_file> --dir <output_dir> |
生成 Dart(用于 Flutter)的客户端调用代码(请求函数 + 类型定义)。 |
| 生成 Kotlin 客户端代码 | goctl api kt --api <api_file> --dir <output_dir> --pkg xx |
生成 Kotlin 语言的客户端调用代码。 |
| 生成 文档 文件 | goctl api doc --dir <api_dir> --o <output_dir> |
生成Markdown说明文件。--dir:api文件所在目录;--o 文档输出目录。 |
| 生成 Swagger 文档 | goctl api swagger --api <api_file> --dir <output_dir> --filename <filename> |
生成 swagger.json 文件。 --filename:指定输出文件名(可选,默认 swagger.json)。 |
| 自定义文件生成 | goctl api plugin --plugin <plugin_name> --api <api_file> --dir <output_dir> |
使用插件生成自定义文件。 --plugin:插件名称 |
一个包含所有语法块的完整写法如下:
这是主api文件,hello.api。
syntax = "v1"
info (
title: "api 文件完整示例写法"
date: "2025 年 7 月"
version: "v1"
)
import "hello2.api" //使用相对路径,导入其它api文件
// g1
// 定义结构体
type (
UpdateReq {
Arg1 string `json:"arg1"`
}
ListItem {
Value1 string `json:"value1"`
}
// 定义登陆接口的json请求体
LoginReq {
Username string `json:"username"`
Password string `json:"password"`
}
// 定义登陆接口的json响应体
LoginResp {
Name string `json:"name"`
}
FormExampleReq {
Name string `form:"name"`
}
PathExampleReq {
// path 标签修饰的 id 必须与请求路由中的片段对应,如
// id 在 service 语法块的请求路径上一定会有 :id 对应,见下文。
ID string `path:"id"`
}
PathExampleResp {
Name string `json:"name"`
}
)
// g2
type (
Base {
Code int `json:"code"`
Msg string `json:"msg"`
}
UserInfo {
Id int64 `json:"id"`
Name string `json:"name"`
Desc string `json:"desc"`
}
GetUserInfoReq {
Id int64 `json:"id"`
}
Nested {
Foo string `json:"foo"`
}
GetUserInfoResp {
// api 支持结构体引用
Base
Data UserInfo `json:"data"`
Nested Nested `json:"nested"`
}
)
// 定义HTTP服务
// @server 语法块主要用于控制对 HTTP 服务生成时 meta 信息,目前支持功能有:
// 1. 路由分组
// 2. 中间件声明
// 3. 路由前缀
// 4. 超时配置
// 5. jwt 鉴权开关
// 所有声明仅对当前 service 中的路由有效
@server (
jwt: Auth // 对当前 Foo 语法块下的所有路由,开启 jwt 认证,不需要则请删除此行
prefix: /v1 // 对当前 Foo 语法块下的所有路由,新增 /v1 路由前缀,不需要则请删除此行
group: g1 // 对当前 Foo 语法块下的所有路由,路由归并到 g1 目录下,不需要则请删除此行
// 定义一个超时时长为 3 秒的超时配置,这里可填写为 time.Duration 的字符串形式,详情可参考
// https://pkg.go.dev/time#Duration.String
timeout: 3s // 对当前 Foo 语法块下的所有路由进行超时配置,不需要则请删除此行
// 定义一个鉴权控制的中间件,多个中间件以英文逗号分割,如 Middleware1,Middleware2,中间件按声明顺序执行
middleware: AuthInterceptor // 对当前 Foo 语法块下的所有路由添加中间件,只是生成代码框架,逻辑自己填写
// 定义一个请求体限制在 1MB 以内的请求,goctl >= 1.5.0 版本支持
maxBytes: 1048576 // 对当前 Foo 语法块下的所有路由添加请求体大小控制,单位为 byte,goctl 版本 >= 1.5.0 才支持
)
// 微服务名称为Foo
// 定义多个service代码块时,服务名称必须一致
service Foo {
// 定义 http.HandleFunc 转换的go文件名称以及方法,每个接口都要有一个handler
@handler pathExample
// 定义方法为 get
// 路由为/path/example/:id
// 请求体为PathExampleReq
// 响应体为PathExampleResp
get /path/example/:id (PathExampleReq) returns (PathExampleResp)
// 定义没有请求体和响应体的接口,如 ping
@handler ping
get /ping
// 定义只有请求体的接口,如更新信息
@handler update
post /update (UpdateReq)
// 定义只有响应体的结构,如获取全部信息列表
@handler list
get /list returns ([]ListItem)
// 定义有结构体和响应体的接口,如登录
@handler login
post /login (LoginReq) returns (LoginResp)
// 定义表单请求
@handler formExample
post /form/example (FormExampleReq)
}
@server (
prefix: /v2 // 新增v2路由前缀
group: g2 // 当前语法块下的路由并到g2文件夹内
)
// 定义一个名称为 Foo 的服务
service Foo {
// 定义 http.HandleFunc 转换的 go 文件名称及方法,每个接口都会跟一个 handler
@handler getUserInfo
// 定义接口
// 请求方法为 post
// 路由为 /user/info
// 请求体为 GetUserInfoReq
// 响应体为 GetUserInfoResp,响应体必须有 returns 关键字修饰
post

最低0.47元/天 解锁文章
4605

被折叠的 条评论
为什么被折叠?



