go-zero api文件讲解

.api 文件是 go-zero核心契约文件,采用自定义 DSL(领域特定语言)语法。它不依赖 Go 语法,而是以声明式方式定义 HTTP 路由、数据结构、参数校验、鉴权与中间件。goctl 解析该文件后,自动生成路由注册、参数绑定、类型定义等样板代码。

下面按日常开发顺序,系统讲解 .api 语法。


📐 一、完整结构模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
syntax = "v1"

info (
title: "商品服务"
desc: "管理商品上下架与查询"
author: "dev"
email: "dev@example.com"
version: "v1.0.0"
)

// 1. 类型定义区
type ...

// 2. 路由与服务定义区
@server (...)
service product-api {
@handler CreateProduct
post /api/v1/products (CreateReq) returns (ProductResp)
}

🔍 二、核心语法详解

1️⃣ 文件头与元数据

1
2
3
4
5
6
7
8
9
syntax = "v1"  // 必须首行声明,固定为 v1

info (
title: "服务名称"
desc: "功能描述"
author: "作者"
email: "邮箱"
version: "版本号"
)

💡 仅用于生成代码注释与文档,不影响运行逻辑。


2️⃣ 类型定义 (type)

语法与 Go struct 高度相似,支持基础类型、切片、映射、指针及嵌套。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
type CreateReq {
Name string `json:"name" validate:"required,max=50"`
Price float64 `json:"price" validate:"required,min=0"`
Tags []string `json:"tags" validate:"dive,max=20"`
Attributes map[string]string `json:"attributes"`
IsPublished bool `json:"is_published"`
}

type ProductResp {
Id int64 `json:"id"`
Name string `json:"name"`
Price float64 `json:"price"`
CreatedAt string `json:"created_at"` // time.Time 默认序列化为 RFC3339 字符串
}

支持的类型映射

.api 类型 Go 类型 说明
bool, int, int32, int64, uint, float32, float64, string 同名 基础类型
time.Time time.Time JSON 默认 RFC3339 格式
[]T, map[K]V 切片/映射 支持嵌套
*T 指针 用于可选字段

3️⃣ 参数绑定与校验(重点)

通过 struct tag 控制参数来源与校验规则,一个字段可组合多个 tag

Tag 作用 示例
json:"key" JSON 请求体/响应体字段名 json:"user_name"
path:"key" URL 路径参数 /users/:idpath:"id"
form:"key" application/x-www-form-urlencodedmultipart/form-data form:"age"
header:"key" HTTP 请求头 header:"X-Request-Id"
validate:"rules" 参数校验(基于 go-playground/validator validate:"required,min=1,max=100,email"

校验规则速查

1
2
3
4
5
6
required      // 必填
min=1,max=100 // 数值/字符串长度范围
email,url,ip // 格式校验
oneof=red blue green // 枚举值
dive // 对切片/映射元素逐项校验(如 []string 的每个元素 max=20)
omitempty // 空值跳过校验(常与 required 互斥)

⚠️ 使用 validate 需在项目 go.mod 中引入:go get github.com/go-playground/validator/v10


4️⃣ 路由与服务定义 (service)

1
2
3
4
5
6
7
8
9
10
service product-api {
@handler CreateProduct
post /api/v1/products (CreateReq) returns (ProductResp)

@handler GetProduct
get /api/v1/products/:id (GetReq) returns (ProductResp)

@handler DeleteProduct
delete /api/v1/products/:id (DeleteReq) returns (EmptyResp)
}

路由规则

  • 支持 get, post, put, delete, patch, head, options
  • 路径参数用 :name{name}(推荐 :id
  • 请求/响应类型必须提前在 type 中定义
  • @handler 命名规范:动词+资源名(首字母大写),生成 internal/handler/xxxhandler.go

5️⃣ 中间件与全局配置 (@server)

@server 块作用于其下方的所有路由,直到遇到下一个 @serverservice 结束。

1
2
3
4
5
6
7
8
9
10
11
12
@server (
jwt: Auth
middleware: LogMiddleware, RateLimitMiddleware
prefix: /api/v1
timeout: 5000
maxBytes: 1048576
group: product
)
service product-api {
@handler CreateProduct
post /products (CreateReq) returns (ProductResp) // 实际路径: /api/v1/products
}

常用指令

指令 说明
jwt: Auth 开启 JWT 鉴权,校验 Authorization 头(Bearer token)
middleware: M1, M2 应用自定义中间件(需在 handler 目录手动实现或 goctl 模板注入)
prefix: /path 路由前缀
timeout: 5000 请求超时(毫秒),默认 3000
maxBytes: 1048576 请求体最大字节数,默认 1MB
group: name 逻辑分组,不影响路由,仅用于代码生成注释

🔑 jwt: Auth 需配合配置文件:

1
2
3
Auth:
AccessSecret: "your-secret"
AccessExpire: 86400

🧩 三、日常开发最佳实践

✅ 1. 文件拆分与组织

goctl 支持多文件扫描,推荐按模块拆分:

1
2
3
4
api/
├── product.api # 商品模块
├── order.api # 订单模块
└── common.api # 公共类型(分页、响应包装等)

生成命令:goctl api go -api api/ -dir .

✅ 2. 公共类型复用

1
2
3
4
5
6
7
8
9
10
// common.api
type PageReq {
Page int `form:"page" validate:"min=1"`
PageSize int `form:"page_size" validate:"min=1,max=100"`
}

type PageResp<T> {
List []T `json:"list"`
Total int `json:"total"`
}

⚠️ .api 不支持泛型语法 <T>,需手动展开或生成后调整。日常建议直接定义具体类型。

✅ 3. 空请求/响应处理

1
2
3
type Empty {}  // 定义空结构体
// 使用:
get /api/v1/health (Empty) returns (Empty)

✅ 4. 路径参数 vs 查询参数

1
2
3
4
5
6
7
8
9
// 路径参数(RESTful 风格)
get /users/:id (GetUserReq) returns (UserResp)

// 查询参数
type ListReq {
Status int `form:"status"`
Keyword string `form:"keyword"`
}
get /users (ListReq) returns (UserListResp)

🚫 四、常见坑点与避坑指南

坑点 原因 正确做法
goctl 报错 undefined type 类型定义在 service 之后或拼写错误 type 必须放在 service 之前,且名称严格匹配
参数未绑定/为 nil 缺少 json/form/path tag 明确声明绑定来源,go-zero 不会自动推断
校验不生效 未引入 validator 或 tag 拼写错误 go get github.com/go-playground/validator/v10,校验 tag 区分大小写
路由冲突 相同路径+方法重复定义 检查 @handler 与路径是否唯一
修改 .api 后代码未更新 未重新执行 goctl api go 每次改 .api 必须重新生成,勿手动改 types/handler/
time.Time 解析失败 前端传时间戳而非 RFC3339 字符串 int64 接收时间戳,或在 logic 中转换;或前端传 "2024-01-01T00:00:00Z"

📖 五、速查表(打印备用)

语法块 用途 示例
syntax = "v1" 声明解析版本 首行必填
info (...) 元数据 生成注释
type Name { ... } 结构体定义 字段+tag
@handler X 绑定 Logic 方法 首字母大写
method /path (Req) returns (Resp) 路由声明 支持 7 种 HTTP 方法
@server (...) 作用域配置 jwt/middleware/prefix/timeout
path:"x" / form:"x" / json:"x" 参数来源 单选或组合
validate:"..." 参数校验 required,min,max,email,oneof,dive

[up主专用,视频内嵌代码贴在这]