API 结构文档
本文档介绍 Zion 项目运行时 GraphQL API 的底层结构,供开发者在 Debug 时或在外部系统、代码组件或自定义前端中调用 Zion 后端能力时参考。
Zion 的运行时 API 采用统一 GraphQL 入口。数据库读写、行为流调用、AI 智能体会话、外部 API 调用都通过 GraphQL 的 query、mutation 或 subscription 表达,差异主要体现在根字段名称、参数和返回结构。
API 访问地址
HTTP GraphQL
项目运行时的 HTTP GraphQL 地址格式如下:
https://zion-app.functorz.com/zero/{projectExId}/api/graphql-v2其中:
| 参数 | 说明 |
|---|---|
projectExId | Zion 项目的唯一标识。 |
HTTP 请求体采用标准 GraphQL JSON 结构:
{
"query": "mutation CreateBlog($object: blog_insert_input!) { insert_blog_one(object: $object) { id } }",
"operationName": "CreateBlog",
"variables": {
"object": {
"title": "我的第一篇博客"
}
}
}WebSocket Subscription
订阅地址格式如下:
wss://zion-app.functorz.com/zero/{projectExId}/api/graphql-subscription订阅主要用于异步行为流任务、AI 智能体流式结果、数据变化监听等场景。
认证与权限
请求头中可通过 Authorization 传入 JWT:
Authorization: Bearer <jwt>未携带 JWT 时,请求按游客身份执行。携带 JWT 后,后端会根据 JWT 解析当前账号、角色、权限,并在执行数据库、行为流、AI 智能体或外部 API 调用前进行权限校验。
JWT 可通过登录接口获取。用户名密码登录示例如下:
mutation AuthenticateWithUsername($username: String!, $password: String!, $register: Boolean!) {
authenticateWithUsername(username: $username, password: $password, register: $register) {
account {
id
permissionRoles
}
jwt {
token
}
}
}其中 register 为 true 时表示注册并登录,为 false 时表示直接登录。返回的 jwt.token 即可作为后续请求的 Bearer Token。
请求与响应结构
GraphQL operation 分为三类:
更多关于 GraphQL 的介绍,请参考 GraphQL 官方文档 。
| 类型 | 用途 | Zion 中的典型场景 |
|---|---|---|
query | 读取数据 | 查询数据表、查询异步任务结果、调用只读外部 API。 |
mutation | 修改数据或触发动作 | 添加/修改/删除数据、触发行为流、创建 AI 会话、发送 AI 消息、调用外部 API。 |
subscription | 监听结果变化 | 数据库数据变化时,实时获取最新数据。 |
成功响应会返回 data。如果执行中出现异常或字段权限错误,会返回 errors:
{
"data": null,
"errors": [
{
"message": "permission denied",
"path": ["insert_blog_one"]
}
]
}GraphQL 只会返回请求中显式声明的字段。数据库写入类操作中,Zion 会确保 id 字段可用于后续行为引用。
数据库操作
Zion 会根据项目数据模型自动生成数据表对应的 GraphQL 字段。接下来用 Zion 自带的查询、添加、修改、删除、事务处理行为来说明 GraphQL 语法。 以下示例中blog、goods、order 等均代表项目中的数据表名。
字段类型映射
数据表字段会映射为对应的 GraphQL 类型。常见类型如下:
| Zion 数据类型 | GraphQL 类型 | 说明 |
|---|---|---|
文本 | String | 文本。 |
长整数 | bigint | 长整数,常用于 id。 |
无限精度小数 | Decimal | 高精度小数。 |
布尔值 | Boolean | 布尔值。 |
JSONB | jsonb | JSON 对象。 |
日期时间(带时区) | timestamptz | 日期、时间和时间间隔。 |
时间(带时区) | timetz | 日期、时间和时间间隔。 |
日期 | date | 日期、时间和时间间隔。 |
经纬度 | geography | 地理位置。 |
图片 | FZ_Image | 图片。 |
视频 | FZ_Video | 视频。 |
文件 | FZ_File | 文件。 |
媒体字段在 GraphQL 入参中通常以资源 id 表达:单个图片、视频、文件字段对应 {field_name}_id,媒体数组字段对应 {field_name}_ids。例如 cover_image 字段写入时传 cover_image_id。
查询数据
数据查询使用 query 类型。
常见根字段与参数
在 GraphQL 中,**“根字段”**是查询的最外层入口,它决定了你想要执行的操作类型。在 Zion 中,系统会自动将你的表名(如 blog)转化为对应的根字段。
例如,如果你想查询 blog 表的数据列表,根字段就是 blog,并且可以在括号内传入筛选和分页参数:
query {
blog(where: {...}, limit: 10) { # 这里的 blog 就是查询的根字段
id
title
}
}根据查询需求的不同,Zion 提供了以下几种常见的根字段格式:
| 字段格式 | 说明 |
|---|---|
{table_name} | 查询数据列表,支持 where、order_by、limit、offset 等参数。 |
{table_name}_by_pk | 按主键查询单条数据。 |
{table_name}_aggregate | 聚合查询,返回 nodes 和 aggregate。 |
{table_name}_group_by | 分组查询,支持 group_by、having、where、order_by、limit、offset 等参数。 |
fz_{table_name}_by_{column_name} | 地理位置查询。当表中包含地理位置字段时,可用于按距离查询。 |
查询参数
当使用上述根字段(如 {table_name} 或 {table_name}_aggregate)时,通常需要传入查询参数来控制返回的数据范围。常见的筛选、排序和分页参数如下:
| 参数 | 说明 |
|---|---|
where | 筛选条件,类型为 {table_name}_bool_exp。 |
order_by | 排序条件,支持字段排序、关联字段排序、聚合排序。 |
distinct_on | 按指定字段去重。 |
limit | 限制返回条数。 |
offset | 跳过指定条数,用于分页。 |
where 过滤语法
逻辑运算符:
| 运算符 | 说明 |
|---|---|
_and | 多个条件同时满足。 |
_or | 多个条件满足任意一个。 |
_not | 对条件取反。 |
比较运算符:
| 运算符 | 说明 |
|---|---|
_eq / _neq | 等于 / 不等于。 |
_gt / _gte | 大于 / 大于等于。 |
_lt / _lte | 小于 / 小于等于。 |
_in / _nin | 在集合中 / 不在集合中。 |
_like / _ilike | 文本匹配 / 忽略大小写文本匹配。 |
_is_null | 是否为空。 |
关联查询:
筛选条件可以沿关联字段继续嵌套。例如查询作者名称为“小明”的博客:
{
"where": {
"author": {
"name": {
"_eq": "小明"
}
}
}
}操作符优先:
在普通的 GraphQL 查询中,我们通常只能直接做简单的“字段 = 值”的比较(例如 age: { _gt: 18 })。但如果想使用数据库内置函数来处理字段(例如提取出时间的月份,再判断它是否等于 12),默认的 GraphQL 结构写不出来。
因此,Zion 提供了一种操作符优先的特殊语法:先写比较操作符(如等于 _eq),然后在左侧(left_operand)调用数据库函数提取字段值,在右侧(right_operand)写上你要比较的目标值。
这就等价于 SQL 中的 WHERE EXTRACT(MONTH FROM created_at) = 12。
例如,查询 account 表中 created_at 月份为 12 的数据:
查询的 GraphQL 语句:
query QueryAccountList($where: account_bool_exp) {
account(where: $where) {
id
username
created_at
}
}对应的 JSON 变量(Variables):
{
"where": {
"_eq": {
"bigint_operand": {
"left_operand": {
"extract_timestamptz": {
"time": { "column": "created_at" },
"unit": "MONTH"
}
},
"right_operand": { "literal": "12" }
}
}
}
}典型查询示例
- 查询列表
查询列表对应 {table_name} 根字段,通常搭配筛选、排序和分页参数使用:
查询列表示例:
query QueryBlogList($where: blog_bool_exp, $limit: Int, $offset: Int) {
blog(where: $where, order_by: { id: desc }, limit: $limit, offset: $offset) {
id
title
author_id
}
}对应的 JSON 变量(Variables):
{
"where": {
"_and": [
{
"author_id": {
"_eq": 10001
}
},
{
"title": {
"_ilike": "%Zion%"
}
}
]
},
"limit": 20,
"offset": 0
}- 按主键查询
按主键查询对应 {table_name}_by_pk 根字段,用于精确获取单条数据:
query QueryBlogByPk($id: bigint!) {
blog_by_pk(id: $id) {
id
title
content
}
}- 聚合查询
聚合查询对应 {table_name}_aggregate 根字段,支持与查询列表相同的 where 等参数,可以同时返回数据节点(nodes)和聚合结果(aggregate):
query QueryBlogAggregate($where: blog_bool_exp) {
blog_aggregate(where: $where) {
nodes {
id
title
}
aggregate {
count
max {
id
}
}
}
}添加数据
数据添加操作使用 mutation 类型。
常见根字段与参数
单条添加组装为 insert_{table_name}_one 的 GraphQL 树,批量添加组装为 insert_{table_name}。
| 字段格式 | 说明 |
|---|---|
insert_{table_name}_one | 单条添加。 |
insert_{table_name} | 批量添加。 |
当使用上述根字段时,通常需要传入以下参数:
| 参数 | 说明 |
|---|---|
object | 单条添加时传入,包含要添加的数据字段及值的 JSON 对象。 |
objects | 批量添加时传入,包含多个 object 的 JSON 数组。 |
on_conflict | 冲突处理策略,当插入的数据与已有数据主键或唯一约束冲突时的处理方式。 |
典型添加示例
- 单条添加
查询的 GraphQL 语句:
mutation($object: blog_insert_input!, $on_conflict: blog_on_conflict!) {
insert_blog_one(object: $object, on_conflict: $on_conflict) {
id
}
}对应的 JSON 变量:
{
"object": {
"title": "我的第一篇博客",
"content": "这是博客的内容。",
"author_id": 10001
},
"on_conflict": {
"constraint": "unique_title",
"update_columns": []
}
}on_conflict.update_columns 为空数组时,对应 Zion 前端“添加”行为中的“忽略并跳过”。指定全部字段数组时,对应“修改原有数据”。
- 批量添加
查询的 GraphQL 语句:
mutation(
$objects: [blog_insert_input!]!,
$on_conflict: blog_on_conflict!
) {
insert_blog(
objects: $objects,
on_conflict: $on_conflict
) {
returning {
id
}
}
}对应的 JSON 变量:
{
"objects": [
{
"title": "我的第一篇博客",
"content": "这是第一篇博客的内容。",
"author_id": 10001
},
{
"title": "第二篇博客",
"content": "更多精彩内容敬请期待。",
"author_id": 10001
}
],
"on_conflict": {
"constraint": "unique_title",
"update_columns": ["title", "content", "author_id"]
}
}修改数据
数据修改操作使用 mutation 类型。
常见根字段与参数
修改数据对应以下两种常见的根字段格式:
| 字段格式 | 说明 |
|---|---|
update_{table_name} | 批量修改,根据条件修改多条数据。 |
update_{table_name}_by_pk | 按主键修改单条数据。 |
当使用上述根字段时,通常需要传入以下参数:
| 参数 | 说明 |
|---|---|
where | 批量修改时传入,筛选要修改的数据条件,类型为 {table_name}_bool_exp。 |
pk_columns | 按主键修改时传入,包含主键字段的对象。 |
_set | 用于直接设置字段的新值。 |
_inc | 用于对数值类型字段进行原子增减操作。 |
典型修改示例
- 批量修改
以下是以商品库存扣减 2 件且限制 库存数 >= 2 为例:
查询的 GraphQL 语句:
mutation update_goods(
$where: goods_bool_exp!,
$inc: goods_inc_input
) {
update_goods(
where: $where,
_inc: $inc
) {
returning {
id
stock
}
}
}对应的 JSON 变量(Variables):
{
"where": {
"_and": [
{
"id": {
"_eq": 10001
}
},
{
"stock": {
"_gte": 2
}
}
]
},
"inc": {
"stock": -2
}
}- 按主键修改
按主键修改时,使用 update_{table_name}_by_pk:
查询的 GraphQL 语句:
mutation UpdateGoodsByPk($pk_columns: goods_pk_columns_input!, $set: goods_set_input) {
update_goods_by_pk(pk_columns: $pk_columns, _set: $set) {
id
name
}
}对应的 JSON 变量(Variables):
{
"pk_columns": {
"id": 10001
},
"set": {
"name": "新商品名称",
"stock": 100
}
}删除数据
数据删除操作使用 mutation 类型。Zion 的“删除”行为会将获取到的参数组装成带有 where 过滤参数的 GraphQL 报文。
常见根字段与参数
删除数据对应以下两种常见的根字段格式:
| 字段格式 | 说明 |
|---|---|
delete_{table_name} | 批量删除,根据条件删除多条数据。 |
delete_{table_name}_by_pk | 按主键删除单条数据。 |
当使用上述根字段时,通常需要传入以下参数:
| 参数 | 说明 |
|---|---|
where | 批量删除时传入,筛选要删除的数据条件,类型为 {table_name}_bool_exp。 |
id | 按主键删除时传入,主键的值。 |
典型删除示例
- 批量删除
查询的 GraphQL 语句:
mutation($where: order_bool_exp!) {
delete_order(where: $where) {
returning {
id
}
}
}对应的 JSON 变量(Variables):
{
"where": {
"_and": [
{ "id": { "_eq": 1 } },
{ "user_id": { "_eq": 1000000000000001 } }
]
}
}- 按主键删除
按主键删除时,使用 delete_{table_name}_by_pk:
查询的 GraphQL 语句:
mutation DeleteOrderByPk($id: bigint!) {
delete_order_by_pk(id: $id) {
id
}
}对应的 JSON 变量(Variables):
{
"id": 10001
}事务处理
Zion 的“事务处理”行为会将所有添加、修改或删除子行为统一拼接在同一个请求中发出。以下是以提交订单并扣减商品库存为例:
事务处理的 GraphQL 语句:
mutation(
$objects_order: [order_insert_input!]!,
$on_conflict_order: order_on_conflict!,
$where_product: product_bool_exp!,
$inc_product: product_inc_input!
) {
# 步骤 1:添加订单
step1_insert: insert_order(
objects: $objects_order,
on_conflict: $on_conflict_order
) {
returning {
id
}
}
# 步骤 2:修改商品库存
step2_update: update_product(
where: $where_product,
_inc: $inc_product
) {
returning {
id
}
}
}对应的 JSON 变量(Variables):
{
"objects_order": [{
"user_id": 10001,
"amount": 99.0,
"product_id": 20001
}],
"on_conflict_order": {
"constraint": "",
"update_columns": []
},
"where_product": {
"_and": [
{
"id": {
"_eq": 20001
}
},
{
"stock": {
"_gte": 1
}
}
]
},
"inc_product": {
"stock": -1
}
}同一个 mutation 中可以放入多个根字段,并通过别名(如 step1_insert、step2_update)区分返回结果。数据库写入会在后端事务中执行;如果某一步失败,事务内的数据库变更会回滚。
行为流调用
行为流适合封装多步骤后端逻辑。Zion 运行时提供同步和异步两类行为流调用方式,主要使用 mutation 触发动作,使用 query 或 subscription 获取异步结果。
常见根字段与参数
行为流调用对应以下几种常见的根字段格式:
| 字段格式 | 类型 | 说明 |
|---|---|---|
fz_invoke_action_flow | mutation | 同步调用指定版本的行为流,并在同一次请求返回输出。 |
fz_invoke_action_flow_default_by_latest_version | mutation | 同步调用默认或最新版本的行为流。 |
fz_create_action_flow_task | mutation | 异步创建行为流任务,返回任务 id。 |
fz_listen_action_flow_result | subscription | 监听异步行为流任务的状态和输出。 |
fz_action_flow_result | query | 主动查询异步行为流任务的当前结果。 |
当使用上述根字段时,通常需要传入以下参数:
| 参数 | 说明 |
|---|---|
actionFlowId | 行为流的唯一标识。 |
versionId | 行为流的版本号。在调用最新版本时可为空。 |
args | 传入行为流的入参,JSON 格式。 |
taskId | 异步行为流任务的 id。 |
典型调用示例
同步调用
同步行为流通过 fz_invoke_action_flow 调用,并在同一次 HTTP 请求中返回行为流输出。
查询的 GraphQL 语句:
mutation InvokeActionFlow($actionFlowId: String!, $versionId: Int!, $args: Json!) {
fz_invoke_action_flow(actionFlowId: $actionFlowId, versionId: $versionId, args: $args)
}对应的 JSON 变量(Variables):
{
"actionFlowId": "d3ea4f95-5d34-46e1-b940-91c4028caff5",
"versionId": 3,
"args": {
"order_id": 10001,
"amount": 99
}
}同步调用也支持使用 fz_invoke_action_flow_default_by_latest_version。该字段允许 versionId 为空,由运行时使用默认或最新版本:
mutation InvokeLatestActionFlow($actionFlowId: String!, $versionId: Int, $args: Json!) {
fz_invoke_action_flow_default_by_latest_version(
actionFlowId: $actionFlowId,
versionId: $versionId,
args: $args
)
}对应的 JSON 变量(Variables):
{
"actionFlowId": "d3ea4f95-5d34-46e1-b940-91c4028caff5",
"args": {
"order_id": 10001,
"amount": 99
}
}异步调用
异步行为流先通过 fz_create_action_flow_task 创建任务,返回任务 id:
创建任务的 GraphQL 语句:
mutation CreateActionFlowTask($actionFlowId: String!, $versionId: Int, $args: Json!) {
fz_create_action_flow_task(actionFlowId: $actionFlowId, versionId: $versionId, args: $args)
}对应的 JSON 变量(Variables):
{
"actionFlowId": "d3ea4f95-5d34-46e1-b940-91c4028caff5",
"versionId": 3,
"args": {
"order_id": 10001,
"amount": 99
}
}返回示例:
{
"data": {
"fz_create_action_flow_task": 1020000000000001
}
}随后通过 Subscription 监听任务结果:
监听结果的 GraphQL 语句:
subscription ListenActionFlowTask($taskId: Long!) {
fz_listen_action_flow_result(taskId: $taskId) {
status
output
}
}对应的 JSON 变量(Variables):
{
"taskId": 1020000000000001
}也可以通过 Query 主动查询任务当前结果:
查询结果的 GraphQL 语句:
query QueryActionFlowResult($taskId: Long!) {
fz_action_flow_result(taskId: $taskId) {
status
output
}
}对应的 JSON 变量(Variables):
{
"taskId": 1020000000000001
}行为流任务结果的 output 和 status 结构如下:
| 字段 | 类型 | 说明 |
|---|---|---|
status | TaskStatus | 任务状态。常见值包括 CREATED、PROCESSING、COMPLETED、FAILED、STREAMING、TIME_OUT。 |
output | Json | 行为流输出节点返回的数据。 |
AI 智能体调用
Zion AI 智能体使用 mutation 触发调用,使用 subscription 获取结果。
AI 智能体的输入参数来自智能体配置。文本、数字等普通参数直接按参数名传入;图片、视频、文件等媒体参数需要传资源 id,并在参数名后追加 _id。如果输入是媒体数组,也使用 _ids 后缀并传入 id 数组。例如智能体配置中有一个视频输入 video,调用时应传 video_id: 1030000000000002。
常见根字段与参数
AI 智能体调用对应以下几种常见的根字段格式:
| 字段格式 | 类型 | 说明 |
|---|---|---|
fz_zai_create_conversation | mutation | 创建智能体会话,返回会话 id。 |
fz_zai_listen_conversation_result | subscription | 监听智能体会话的流式或最终结果。 |
fz_zai_send_ai_message | mutation | 继续会话,向已有会话发送新消息,返回消息 id。 |
fz_zai_stop_responding | mutation | 停止当前会话中 AI 的响应。 |
fz_zai_delete_conversation | mutation | 删除指定的会话。 |
当使用上述根字段时,通常需要传入以下参数:
| 参数 | 说明 |
|---|---|
inputArgs | 一次性任务的提示词或创建会话时的初始入参映射。 |
zaiConfigId | 智能体配置的唯一标识。 |
conversationId | 会话 ID。 |
text / imageIds / fileId / videoId | 继续会话时,发送新消息的文本和多媒体资源。 |
典型调用示例
创建并监听会话
创建会话的 GraphQL 语句:
mutation ZAICreateConversation($inputArgs: Map_String_ObjectScalar!, $zaiConfigId: String!) {
fz_zai_create_conversation(inputArgs: $inputArgs, zaiConfigId: $zaiConfigId)
}对应的 JSON 变量(Variables):
{
"zaiConfigId": "zai_01HZXEXAMPLE",
"inputArgs": {
"question": "请总结这篇文章",
"article_id": 10001,
"cover_image_id": 1020000000000097
}
}创建会话后,通过 Subscription 监听流式或最终结果:
监听会话的 GraphQL 语句:
subscription ListenZAIConversation($conversationId: Long!) {
fz_zai_listen_conversation_result(conversationId: $conversationId) {
conversationId
status
data
reasoningContent
images {
id
url
}
}
}对应的 JSON 变量(Variables):
{
"conversationId": 1
}流式输出说明:流式文本输出会多次推送
STREAMING状态,最后一次COMPLETED状态中的data会包含汇总后的完整输出。结构化输出不会流式返回,最终COMPLETED消息中的data会是符合智能体结构化对象。图片输出模型会在images字段中返回生成图片的资源对象。
会话消息管理
多轮对话中,可以向已有会话发送新消息、停止响应或删除会话。
发送新消息的 GraphQL 语句:
mutation ZAISendAiMessage(
$conversationId: Long!,
$text: String,
$imageIds: [Long],
$fileId: Long,
$videoId: Long
) {
fz_zai_send_ai_message(
conversationId: $conversationId,
text: $text,
imageIds: $imageIds,
fileId: $fileId,
videoId: $videoId
)
}对应的 JSON 变量(Variables):
{
"conversationId": 1,
"text": "这段代码有点问题,请帮忙看看。",
"imageIds": [1020000000000097]
}(发送后继续订阅同一个 conversationId 即可获得后续结果)
停止响应的 GraphQL 语句:
mutation StopZAIResponding($conversationId: Long!) {
fz_zai_stop_responding(conversationId: $conversationId)
}对应的 JSON 变量(Variables):
{
"conversationId": 1
}删除会话的 GraphQL 语句:
mutation DeleteZAIConversation($conversationId: Long!) {
fz_zai_delete_conversation(conversationId: $conversationId)
}对应的 JSON 变量(Variables):
{
"conversationId": 1
}外部 API 调用
Zion 支持在项目中配置外部 API,并将其暴露为 GraphQL 字段。外部 API 可以作为 query 或 mutation 调用,取决于该 API 在 Zion 中的类型配置。
常见根字段与参数
外部 API 有两套命名形式及对应的根字段格式:
| 字段格式 | 说明 |
|---|---|
operation_{thirdPartyApiId} | 旧版第三方 API,以导入的 OpenAPI operation id 生成 GraphQL 字段。 |
fz_api_{apiId} | 新版 API Workspace,以 API Workspace 中的 API 标识生成 GraphQL 字段。 |
当使用上述根字段时,通常需要传入相应的请求参数:
| 参数 | 说明 |
|---|---|
fz_body | 旧版第三方 API 的请求体参数,通常为 JSON 结构。 |
Authorization | 旧版第三方 API 的请求鉴权头。其他路径或查询参数也会按 API 配置生成为 GraphQL 参数。 |
input | 新版 API Workspace 的请求参数,类型通常为 fz_api_{api_name}_input。 |
提示:当外部 API 被配置在行为流节点中时,外部调用不会单独暴露给前端,而是作为行为流执行过程的一部分。此时前端调用的是行为流相关字段。如果外部 API 返回非 2xx 状态码,行为流会将该节点视为执行失败。
典型调用示例
1. 旧版第三方 API
旧版第三方 API 调用后应先检查 responseCode,当外部 API 返回 4xx 或 5xx 时,field_200_json 可能为空。
查询的 GraphQL 语句:
mutation CreateCalendarEvent(
$summary: String,
$location: String,
$authorization: String
) {
operation_create_calendar_event(
fz_body: {
summary: $summary,
location: $location
},
Authorization: $authorization
) {
responseCode
field_200_json {
id
status
htmlLink
}
}
}对应的 JSON 变量(Variables):
{
"summary": "项目周会",
"location": "会议室 A",
"authorization": "Bearer third_party_token"
}2. 新版 API Workspace
新版 API Workspace 的响应通常包含了 HTTP 状态码、内容类型以及对应配置好的结构化响应字段。
查询的 GraphQL 语句:
mutation CallApi($input: fz_api_create_order_input!) {
fz_api_create_order(input: $input) {
responseCode
responseStatus
responseContentType
fz_api_create_order_response {
order_id
status
}
}
}对应的 JSON 变量(Variables):
{
"input": {
"order_id": 10001,
"amount": 99.0
}
}