← 返回文章列表

go-zero的API語言

記錄 go-zero API 描述語言的語法與程式碼生成方式。

go

api 是 go-zero 自研的領域特性語言,旨在實現人性化的基礎描述原因,作為生成 HTTP 服務最基本的描述語言。可以透過官方提供的 goctl 工具實現 api 向結構化專案的轉換。

概述

api 領域特性語言包含語法版本,info 塊,結構體宣告,服務描述等幾大塊語法組成,其中結構體和 Golang 結構體語法幾乎一樣,只是移除了 struct 關鍵字。

syntax 語句

syntax 語句用於標記 api 語言的版本,不同的版本可能語法結構有所不同,隨著版本的提升會做不斷的最佳化,當前版本為 v1。

syntax = "v1"

info 語句

info 語句是 api 語言的 meta 資訊,其僅用於對當前 api 檔案進行描述,暫不參與程式碼生成,其和註釋還是有一些區別,註釋一般是依附某個 syntax 語句存在,而 info 語句是用於描述整個 api 資訊的。

// 不包含 key-value 的 info 块
info ()

// 包含 key-value 的 info 块
info (
    foo: "bar"
    bar:
)

import語句

import 語句是在 api 中引入其他 api 檔案的語法塊,其支援相對路徑和絕對路徑,不支援 package 設計。

// 单行 import
import "foo"
import "/path/to/file"

// import 组
import ()
import (
    "bar"
    "relative/to/file"
)

資料型別

api 中的資料型別基本沿用了 Golang 的資料型別,用於對 rest 服務的請求/響應體結構的描述,不支援 package 如 time.Time。

// 空结构体
type Foo {}

// 单个结构体
type Bar {
    Foo int               `json:"foo"`
    Bar bool              `json:"bar"`
    Baz []string          `json:"baz"`
    Qux map[string]string `json:"qux"`
}

type Baz {
    Bar    `json:"baz"`
    Array [3]int `json:"array"`
    // 结构体内嵌 goctl 1.6.8 版本支持
    Qux {
        Foo string `json:"foo"`
        Bar bool   `json:"bar"`
    } `json:"baz"`
}

// 空结构体组
type ()

// 结构体组
type (
    Int int
    Integer = int
    Bar {
        Foo int               `json:"foo"`
        Bar bool              `json:"bar"`
        Baz []string          `json:"baz"`
        Qux map[string]string `json:"qux"`
    }
)

service語句-@service

service 語句是對 HTTP 服務的直觀描述,包含請求 handler,請求方法,請求路由,請求體,響應體,jwt 開關,中介軟體宣告等定義。

// 空内容
@server()

// 有内容
@server (
    // jwt 声明
    // 如果 key 固定为 “jwt:”,则代表开启 jwt 鉴权声明
    // value 则为配置文件的结构体名称
    jwt: Auth

    // 路由前缀
    // 如果 key 固定为 “prefix:”
    // 则代表路由前缀声明,value 则为具体的路由前缀值,字符串中没让必须以 / 开头
    prefix: /v1

    // 路由分组
    // 如果 key 固定为 “group:”,则代表路由分组声明
    // value 则为具体分组名称,在 goctl生成代码后会根据此值进行文件夹分组
    group: Foo

    // 中间件
    // 如果 key 固定为 middleware:”,则代表中间件声明
    // value 则为具体中间件函数名称,在 goctl生成代码后会根据此值进生成对应的中间件函数
    middleware: AuthInterceptor

    // 超时控制
    // 如果 key 固定为  timeout:”,则代表超时配置
    // value 则为具体中duration,在 goctl生成代码后会根据此值进生成对应的超时配置
    timeout: 3s

    // 其他 key-value,除上述几个内置 key 外,其他 key-value
    // 也可以在作为 annotation 信息传递给 goctl 及其插件,但就
    // 目前来看,goctl 并未使用。
    foo: bar
)

服務條目

服務條目(ServiceItemStmt)是對單個 HTTP 請求的描述,包括 @doc 語句,@handler 語句,路由語句資訊。

@doc 語句

@doc 語句是對單個路由的 meta 資訊描述,一般為 key-value 值,可以傳遞給 goctl 及其外掛來進行擴充套件生成。

// 单行 @doc
@doc "foo"

// 空 @doc 组
@doc ()

// 有内容的 @doc 组
@doc (
    foo: "bar"
    bar: "baz"
)

@handler 語句

@handler 語句是對單個路由的 handler 資訊控制,主要用於生成 golang http.HandleFunc 的實現轉換方法。

@handler foo

路由語句

路由語句是對單此 HTTP 請求的具體描述,包括請求方法,請求路徑,請求體,響應體資訊。

// 没有请求体和响应体的写法
get /ping

// 只有请求体的写法
get /foo (foo)

// 只有响应体的写法
post /foo returns (foo)

// 有请求体和响应体的写法
post /foo (foo) returns (bar)

一個完整service

// 带 @server 的写法
@server (
    prefix: /v1
    group: Login
)
service user {
    @doc "登录"
    @handler login
    post /user/login (LoginReq) returns (LoginResp)

    @handler getUserInfo
    get /user/info/:id (GetUserInfoReq) returns (GetUserInfoResp)
}
@server (
    prefix: /v1
    middleware: AuthInterceptor
)
service user {
    @doc "登录"
    @handler login
    post /user/login (LoginReq) returns (LoginResp)

    @handler getUserInfo
    get /user/info/:id (GetUserInfoReq) returns (GetUserInfoResp)
}


// 不带 @server 的写法
service user {
    @doc "登录"
    @handler login
    post /user/login (LoginReq) returns (LoginResp)

    @handler getUserInfo
    get /user/info/:id (GetUserInfoReq) returns (GetUserInfoResp)
}

完整示例

syntax = "v1"

info (
    title:   "api 文件完整示例写法"
    desc:    "演示如何编写 api 文件"
    author:  "keson.an"
    date:    "2022 年 12 月 26 日"
    version: "v1"
)

type UpdateReq {
    Arg1 string `json:"arg1"`
}

type ListItem {
    Value1 string `json:"value1"`
}

type LoginReq {
    Username string `json:"username"`
    Password string `json:"password"`
}

type LoginResp {
    Name string `json:"name"`
}

type FormExampleReq {
    Name string `form:"name"`
}

type PathExampleReq {
    // path 标签修饰的 id 必须与请求路由中的片段对应,如
    // id 在 service 语法块的请求路径上一定会有 :id 对应,见下文。
    ID string `path:"id"`
}

type PathExampleResp {
    Name string `json:"name"`
}

@server (
    jwt:        Auth // 对当前 Foo 语法块下的所有路由,开启 jwt 认证,不需要则请删除此行
    prefix:     /v1 // 对当前 Foo 语法块下的所有路由,新增 /v1 路由前缀,不需要则请删除此行
    group:      g1 // 对当前 Foo 语法块下的所有路由,路由归并到 g1 目录下,不需要则请删除此行
    timeout:    3s // 对当前 Foo 语法块下的所有路由进行超时配置,不需要则请删除此行
    middleware: AuthInterceptor // 对当前 Foo 语法块下的所有路由添加中间件,不需要则请删除此行
    maxBytes:   1048576 // 对当前 Foo 语法块下的所有路由添加请求体大小控制,单位为 byte,goctl 版本 >= 1.5.0 才支持
)
service Foo {
    // 定义没有请求体和响应体的接口,如 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)

    // 定义 path 参数
    @handler pathExample
    get /path/example/:id (PathExampleReq) returns (PathExampleResp)
}

參考資料

API 規範

API 定義完整示例

關於這篇文章的日期

舊日期 2025-01-16 與文章發布記錄不符,現按舊站可確認的首次發布日 2026-01-25 整理。實際創作日期尚無法確認。

原始日期: 2025-01-16 21:15:06 +0800