.agents/design/api/index.md
packages/global/openapi/ 中,类型从 schema 导出schema.parse() 验证入参和出参packages/global/openapi/
├── api.ts # 公共 Schema (分页等)
├── type.ts # OpenAPIPath 类型
├── tag.ts # API 标签定义
├── index.ts # 用户 API 文档入口
├── admin.ts # 管理员 API 文档入口
└── core/
└── dataset/
├── api.ts # ← Schema 定义 (入参/出参)
├── index.ts # ← OpenAPI 路由注册
├── collection/
│ ├── api.ts
│ └── index.ts
└── data/
├── api.ts
└── index.ts
文件位置: packages/global/openapi/[module]/api.ts
import { z } from 'zod';
import { ObjectIdSchema } from '../../../common/type/mongo';
import { ParentIdSchema } from '../../../common/parentFolder/type';
/* ============================================================================
* API: 创建知识库
* Route: POST /api/core/dataset/create
* ============================================================================ */
// 入参 Schema
export const CreateDatasetBodySchema = z.object({
parentId: ParentIdSchema.meta({
example: '68ad85a7463006c963799a05',
description: '父级文件夹 ID'
}),
name: z.string().meta({
example: '我的知识库',
description: '知识库名称'
})
});
export type CreateDatasetBodyType = z.infer<typeof CreateDatasetBodySchema>;
// 出参 Schema
export const CreateDatasetResponseSchema = ObjectIdSchema.meta({
example: '68ad85a7463006c963799a05',
description: '新创建的知识库 ID'
});
export type CreateDatasetResponseType = z.infer<typeof CreateDatasetResponseSchema>;
文件位置: projects/app/src/pages/api/[path]/[route].ts
import { NextAPI } from '@/service/middleware/entry';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import {
CreateDatasetBodySchema,
CreateDatasetResponseSchema,
type CreateDatasetResponseType
} from '@fastgpt/global/openapi/core/dataset/api';
// ❌ 不要在路由文件中重导出类型别名
// export type DatasetCreateBodyType = CreateDatasetBodyType;
async function handler(req: ApiRequestProps): Promise<CreateDatasetResponseType> {
// 1. 入参验证
const { parentId, name } = CreateDatasetBodySchema.parse(req.body);
// 2. 业务逻辑
const datasetId = await createDataset({ parentId, name });
// 3. 出参验证
return CreateDatasetResponseSchema.parse(datasetId);
}
export default NextAPI(handler);
3a. 添加标签 (如果是新模块): packages/global/openapi/tag.ts
export const DevApiTagsMap = {
// Dataset
datasetCommon: '知识库管理', // ← 新增
datasetCollection: '集合管理',
// ...
};
3b. 注册路由: packages/global/openapi/[module]/index.ts
import type { OpenAPIPath } from '../../type';
import { DevApiTagsMap } from '../../tag';
import { CreateDatasetBodySchema } from './api';
export const DatasetPath: OpenAPIPath = {
'/core/dataset/create': {
post: {
summary: '创建知识库',
description: '创建新的知识库,支持多种类型',
tags: [DevApiTagsMap.datasetCommon],
requestBody: {
content: {
'application/json': {
schema: CreateDatasetBodySchema
}
}
},
responses: {
200: {
description: '成功返回新创建的知识库 ID'
}
}
}
},
...DatasetCollectionPath,
...DatasetDataPath
};
前端直接从 openapi 包导入类型,不从 API 路由文件导入。
// ✅ 正确: 从 openapi 导入
import type { CreateDatasetBodyType } from '@fastgpt/global/openapi/core/dataset/api';
// ❌ 错误: 从路由文件导入
import type { DatasetCreateBodyType } from '@/pages/api/core/dataset/create';
// ❌ 错误: 从旧的 global 文件导入
import type { CreateDatasetParams } from '@/global/core/dataset/api';
测试同样直接从 openapi 导入类型。
import createHandler from '@/pages/api/core/dataset/create';
import type {
CreateDatasetBodyType,
CreateDatasetResponseType
} from '@fastgpt/global/openapi/core/dataset/api';
import { Call } from '@test/utils/request';
const res = await Call<CreateDatasetBodyType, {}, CreateDatasetResponseType>(createHandler, {
auth: users.members[0],
body: { name: 'test', intro: 'intro', avatar: 'avatar', type: DatasetTypeEnum.dataset }
});
使用已有的公共 Schema,避免重复定义。
| Schema | 说明 | 导入路径 |
|---|---|---|
ObjectIdSchema | MongoDB ObjectId (24位hex,自动将 ObjectId 对象转为 string) | @fastgpt/global/common/type/mongo |
ParentIdSchema | 父级 ID (z.string().nullish()) | @fastgpt/global/common/parentFolder/type |
ObjectId 陷阱: MongoDB 返回的 _id 是 ObjectId 对象,不是 string。直接用 z.string() 验证出参会报错。必须使用 ObjectIdSchema(内置 preprocess 自动转换)。
// ❌ 出参验证会失败 — ObjectId 不是 string
export const ResponseSchema = z.string();
return ResponseSchema.parse(document._id); // ZodError!
// ✅ ObjectIdSchema 内置 preprocess,自动转换
import { ObjectIdSchema } from '../../../common/type/mongo';
export const ResponseSchema = ObjectIdSchema;
return ResponseSchema.parse(document._id); // "68ad85a7463006c963799a05"
| Schema | 说明 | 导入路径 |
|---|---|---|
PaginationSchema | 偏移分页 (pageSize, offset, pageNum) | @fastgpt/global/openapi/api |
PaginationResponseSchema<T> | 分页响应 (total, list) | @fastgpt/global/openapi/api |
LinkedPaginationSchema | 游标分页 (pageSize, nextId, prevId) | @fastgpt/global/openapi/api |
LinkedListResponseSchema<T> | 游标分页响应 (list, hasMorePrev, hasMoreNext) | @fastgpt/global/openapi/api |
| Schema | 说明 | 导入路径 |
|---|---|---|
OutLinkChatAuthSchema | 外部链接认证 (shareId, outLinkUid, teamId, teamToken) | @fastgpt/global/support/permission/chat |
已有的业务级 Schema 可以直接在出入参中复用:
| Schema | 说明 | 导入路径 |
|---|---|---|
ApiDatasetServerSchema | 第三方知识库服务器配置 | @fastgpt/global/core/dataset/apiDataset/type |
EmbeddingModelItemSchema | 向量模型信息 | @fastgpt/global/core/ai/model.schema |
遇到复杂嵌套类型时,优先查找是否已有对应的 zod schema 可复用。
所有字段必须有 description,推荐有 example:
z.string().meta({
example: '[email protected]',
description: '用户邮箱'
})
// 可选 (undefined)
z.string().optional().meta({ description: '...' })
// 可空 (undefined | null) — 用于 parentId 等场景
z.string().nullish().meta({ description: '...' })
import { DatasetTypeEnum } from '../../../core/dataset/constants';
// TypeScript enum — 使用 z.enum
z.enum(DatasetTypeEnum).meta({
example: DatasetTypeEnum.dataset,
description: '知识库类型'
})
嵌套对象优先抽取为独立 Schema 复用:
const FileItemSchema = z.object({
fileId: z.string().meta({ example: 'temp/abc.pdf', description: '文件 ID' }),
name: z.string().meta({ example: '文档.pdf', description: '文件名' })
});
export const CreateWithFilesBodySchema = z.object({
files: z.array(FileItemSchema).meta({ description: '文件列表' })
});
将旧 API 迁移到 zod schema 规范时,除了上述 5 步外,还需要:
旧类型通常在 projects/app/src/global/ 或路由文件中。迁移后:
使用全局搜索找到所有旧类型的引用,逐一更新:
# 搜索旧类型名
grep -r "CreateDatasetParams" projects/app/src/
需要更新的典型位置:
projects/app/src/web/ — 前端 API 调用projects/app/src/pageComponents/ — 页面组件projects/app/test/ — 测试文件// ❌ 删除这些
export type DatasetCreateQuery = {};
export type DatasetCreateBodyType = CreateDatasetBodyType;
export type DatasetCreateResponse = CreateDatasetResponseType;
Schema 文件 (packages/global/openapi/.../api.ts):
z.infer<typeof Schema> 类型descriptionObjectIdSchema,父级 ID 使用 ParentIdSchemaAPI 路由文件 (projects/app/src/pages/api/.../route.ts):
Schema.parse(req.body) 或 Schema.parse(req.query)Schema.parse(result)OpenAPI 注册 (packages/global/openapi/.../index.ts):
DevApiTagsMap 标签tag.ts 中添加标签类型引用:
@fastgpt/global/openapi/ 导入类型@fastgpt/global/openapi/ 导入类型@/pages/api/...) 导入类型packages/global/openapi/core/dataset/api.tspackages/global/openapi/core/dataset/index.tsprojects/app/src/pages/api/core/dataset/create.tsprojects/app/src/web/core/dataset/api.tsprojects/app/test/api/core/dataset/create.test.tspackages/global/openapi/api.tspackages/global/openapi/tag.tsVersion: 2.0 Last Updated: 2026-04-10