| name | api-development |
| description | FastGPT API 开发规范。重点强调使用 zod schema 定义入参和出参,在 API 文档中声明路由信息,编写对应的 OpenAPI 文档,以及在 API 路由中使用 schema.parse 进行验证。 |
FastGPT API 开发规范
FastGPT 项目 API 路由开发的标准化指南,确保 API 的一致性、类型安全和文档完整性。
何时使用此技能
- 开发新的 Next.js API 路由
- 修改现有 API 的入参或出参
- 需要 API 类型定义和文档
- 审查 API 相关代码
核心原则
🔴 必须遵守的规则
- 所有 API 必须使用 zod schema 定义入参和出参
- 必须导出 schema 的 TypeScript 类型
- 必须在 schema 文件头部声明 API 信息(路由、方法、描述、标签)
- 入参必须使用 schema.parse() 验证
- 函数返回值必须使用 schema.parse() 验证
- 必须编写完整的 OpenAPI 文档
开发流程
步骤 1: 定义 Zod Schema 并声明 API
文件位置: packages/global/openapi/[module]/[api].ts
文件头部必须声明 API 信息:
import { z } from 'zod';
export const GetAppChatLogsBodySchema = PaginationSchema.extend({
appId: z.string().meta({
example: '68ad85a7463006c963799a05',
description: '应用 ID'
}),
dateStart: z.union([z.string(), z.date()]).meta({
example: '2024-01-01T00:00:00.000Z',
description: '开始时间'
}),
dateEnd: z.union([z.string(), z.date()]).meta({
example: '2024-12-31T23:59:59.999Z',
description: '结束时间'
}),
sources: z.array(z.nativeEnum(ChatSourceEnum)).optional().meta({
example: [ChatSourceEnum.api, ChatSourceEnum.online],
description: '对话来源筛选'
})
});
export type getAppChatLogsBody = z.infer<typeof GetAppChatLogsBodySchema>;
export const GetAppChatLogsResponseSchema = z.object({
total: z.number().meta({ example: 100, description: '总记录数' }),
list: z.array(ChatLogItemSchema)
});
export type getAppChatLogsResponseType = z.infer<typeof GetAppChatLogsResponseSchema>;
API 声明规范:
OpenAPI Tag 归属规则:
- 如果接口能力属于通用模块 A,但会被业务模块 B 使用,则该接口必须同时声明 A 模块 tag 和 B 模块 tag。
- 如果同一个通用接口也被业务模块 C 使用,则继续追加 C 模块 tag。
- 通用模块 tag 表示接口能力和实现抽象归属;业务模块 tag 表示该接口应出现在对应业务文档视角里。
- 如果接口只是业务模块自己的状态查询或状态操作,不属于通用模块能力,则只声明业务模块 tag,不要为了实现位置或相邻目录误加通用模块 tag。
- 示例:
协作者管理 是通用权限能力,应用协作者接口需要同时声明 协作者管理 和应用侧 权限管理;获取应用权限、恢复应用继承权限 是应用自身权限状态接口,只声明应用侧 权限管理。
Schema 定义规范:
✅ 字段定义规范
export const GetUserSchema = z.object({
userId: z.string().meta({
example: '68ad85a7463006c963799a05',
description: '用户 ID'
}),
email: z.string().email().meta({
example: 'user@example.com',
description: '用户邮箱'
}),
age: z.number().int().positive().meta({
example: 25,
description: '用户年龄'
}),
status: z.enum(['active', 'inactive']).meta({
example: 'active',
description: '用户状态'
})
});
export const GetUserSchemaBad = z.object({
userId: z.string(),
email: z.string(),
age: z.number(),
status: z.string()
});
✅ 嵌套对象定义
export const AddressSchema = z.object({
street: z.string().meta({ description: '街道地址' }),
city: z.string().meta({ description: '城市' }),
country: z.string().meta({ description: '国家' })
});
export const CreateUserSchema = z.object({
name: z.string().meta({ description: '用户名' }),
address: AddressSchema.meta({ description: '地址信息' })
});
✅ 数组定义
export const GetUserListResponseSchema = z.object({
total: z.number().meta({ example: 100, description: '总数' }),
list: z.array(
z.object({
id: z.string().meta({ description: '用户 ID' }),
name: z.string().meta({ description: '用户名' })
})
).meta({ description: '用户列表' })
});
✅ 可选字段
export const UpdateUserSchema = z.object({
userId: z.string().meta({ description: '用户 ID' }),
name: z.string().optional().meta({ description: '用户名' }),
email: z.string().email().nullish().meta({ description: '用户邮箱' })
});
✅ 分页 Schema
import { PaginationSchema } from '@fastgpt/global/openapi/api';
export const GetUserListSchema = PaginationSchema.extend({
keyword: z.string().optional().meta({ description: '搜索关键词' }),
status: z.enum(['active', 'inactive']).optional().meta({ description: '状态筛选' })
});
✅ 多个 API 的 Schema 文件
export const GetLogKeysQuerySchema = z.object({
appId: z.string().meta({ description: '应用 ID' })
});
export const GetLogKeysResponseSchema = z.object({
logKeys: z.array(AppLogKeysSchema).meta({ description: '日志键列表' })
});
export const UpdateLogKeysBodySchema = z.object({
appId: z.string().meta({ description: '应用 ID' }),
logKeys: z.array(AppLogKeysSchema).meta({ description: '日志键列表' })
});
步骤 2: 实现 API 路由
文件位置: projects/app/src/pages/api/[path]/[route].ts
标准实现模板:
import type { NextApiResponse } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import {
GetAppChatLogsBodySchema,
GetAppChatLogsResponseSchema,
type getAppChatLogsResponseType
} from '@fastgpt/global/openapi/...';
async function handler(
req: ApiRequestProps,
_res: NextApiResponse
): Promise<getAppChatLogsResponseType> {
const { appId, dateStart, dateEnd, sources } = GetAppChatLogsBodySchema.parse(req.body);
const result = await yourBusinessLogic({ appId, dateStart, dateEnd, sources });
return GetAppChatLogsResponseSchema.parse({
list: result.list,
total: result.total
});
}
export default NextAPI(handler);
完整示例:
import type { NextApiResponse } from 'next';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { NextAPI } from '@/service/middleware/entry';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import {
GetAppChatLogsBodySchema,
GetAppChatLogsResponseSchema,
type getAppChatLogsResponseType
} from '@fastgpt/global/openapi/core/app/log/api';
async function handler(
req: ApiRequestProps,
_res: NextApiResponse
): Promise<getAppChatLogsResponseType> {
const { appId, dateStart, dateEnd, sources } = GetAppChatLogsBodySchema.parse(req.body);
await authApp({
req,
authToken: true,
appId,
per: AppReadChatLogPerVal
});
const { list, total } = await getChatLogsFromDB({
appId,
dateStart,
dateEnd,
sources
});
return GetAppChatLogsResponseSchema.parse({
list,
total
});
}
export default NextAPI(handler);
步骤 3: 权限验证 (如需要)
使用 authApp 或其他权限验证函数:
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import { AppWritePerVal } from '@fastgpt/global/support/permission/app/constant';
async function handler(req: ApiRequestProps, res: NextApiResponse) {
const { appId } = YourAPIBodySchema.parse(req.body);
await authApp({
req,
authToken: true,
appId,
per: AppWritePerVal
});
}
步骤 4: 错误处理
使用统一的错误处理:
import { APIError } from '@fastgpt/service/core/error/controller';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
async function handler(req: ApiRequestProps, res: NextApiResponse) {
try {
const { appId } = YourAPIBodySchema.parse(req.body);
if (!appId) {
return Promise.reject(CommonErrEnum.missingParams);
}
} catch (error) {
return APIError(error)(req, res);
}
}
完整开发示例
场景: 创建用户 API
1. 定义 Schema (packages/global/openapi/core/user/api.ts):
import { z } from 'zod';
export const CreateUserBodySchema = z.object({
name: z.string().min(2).max(50).meta({
example: 'Alice',
description: '用户名 (2-50 字符)'
}),
email: z.string().email().meta({
example: 'alice@example.com',
description: '用户邮箱'
}),
age: z.number().int().positive().optional().meta({
example: 25,
description: '用户年龄'
}),
avatar: z.string().url().optional().meta({
example: 'https://example.com/avatar.jpg',
description: '头像 URL'
})
});
export type createUserBodyType = z.infer<typeof CreateUserBodySchema>;
export const CreateUserResponseSchema = z.object({
userId: z.string().meta({ example: '68ad85a7463006c963799a05', description: '用户 ID' }),
name: z.string().meta({ example: 'Alice', description: '用户名' }),
email: z.string().meta({ example: 'alice@example.com', description: '用户邮箱' }),
createdAt: z.date().meta({ example: '2024-01-01T00:00:00.000Z', description: '创建时间' })
});
export type createUserResponseType = z.infer<typeof CreateUserResponseSchema>;
2. 实现 API (projects/app/src/pages/api/core/user/create.ts):
import type { NextApiResponse } from 'next';
import { NextAPI } from '@/service/middleware/entry';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { MongoUser } from '@fastgpt/service/core/user/schema';
import {
CreateUserBodySchema,
CreateUserResponseSchema,
type createUserResponseType
} from '@fastgpt/global/openapi/core/user/api';
async function handler(
req: ApiRequestProps,
_res: NextApiResponse
): Promise<createUserResponseType> {
const { name, email, age, avatar } = CreateUserBodySchema.parse(req.body);
const existingUser = await MongoUser.findOne({ email });
if (existingUser) {
return Promise.reject('Email already exists');
}
const user = await MongoUser.create({
name,
email,
age,
avatar,
createdAt: new Date()
});
return CreateUserResponseSchema.parse({
userId: user._id.toString(),
name: user.name,
email: user.email,
createdAt: user.createdAt
});
}
export default NextAPI(handler);
审查检查清单
🔴 必须检查项 (阻塞性)
Schema 文件 (packages/global/openapi/.../api.ts):
API 路由文件 (projects/app/src/pages/api/.../route.ts):
🟡 推荐检查项 (建议性)
🟢 可选检查项 (优化性)
常见问题和解决方案
问题 1: 缺少 API 声明
错误示例:
import { z } from 'zod';
export const GetUserSchema = z.object({
id: z.string()
});
正确做法:
import { z } from 'zod';
export const GetUserSchema = z.object({
id: z.string().meta({
example: '68ad85a7463006c963799a05',
description: '用户 ID'
})
});
问题 2: 类型不匹配
错误示例:
async function handler(req: ApiRequestProps, res: NextApiResponse) {
const data = YourAPIBodySchema.parse(req.body);
return { success: true, data };
}
正确做法:
async function handler(
req: ApiRequestProps,
_res: NextApiResponse
): Promise<yourAPIResponseType> {
const data = YourAPIBodySchema.parse(req.body);
return YourAPIResponseSchema.parse({
success: true,
data
});
}
问题 3: 缺少 Meta 信息
错误示例:
export const UserSchema = z.object({
id: z.string(),
name: z.string(),
email: z.string()
});
正确做法:
export const UserSchema = z.object({
id: z.string().meta({
example: '68ad85a7463006c963799a05',
description: '用户 ID'
}),
name: z.string().meta({
example: 'Alice',
description: '用户名'
}),
email: z.string().email().meta({
example: 'alice@example.com',
description: '用户邮箱'
})
});
问题 4: 未验证出参
错误示例:
async function handler(req: ApiRequestProps, res: NextApiResponse) {
const { appId } = YourAPIBodySchema.parse(req.body);
const result = await getData(appId);
return result;
}
正确做法:
async function handler(req: ApiRequestProps, res: NextApiResponse) {
const { appId } = YourAPIBodySchema.parse(req.body);
const result = await getData(appId);
return YourAPIResponseSchema.parse(result);
}
问题 5: Schema 复用不当
不好做法:
export const Schema1 = z.object({
id: z.string(),
name: z.string(),
email: z.string()
});
export const Schema2 = z.object({
id: z.string(),
name: z.string(),
email: z.string()
});
正确做法:
export const BaseUserSchema = z.object({
id: z.string().meta({ description: 'ID' }),
name: z.string().meta({ description: '名称' }),
email: z.string().email().meta({ description: '邮箱' })
});
export const Schema1 = z.object({
user: BaseUserSchema
});
export const Schema2 = z.object({
users: z.array(BaseUserSchema)
});
快速参考
API 声明模板
常用标签
- 模块标签:
App, User, Chat, Workflow, Dataset
- 操作类型:
Read, Write, Delete, Update
- 其他:
Admin, Public, Internal
常用 Zod 验证方法
z.string()
.min(2)
.max(50)
.email()
.url()
.uuid()
z.number()
.int()
.positive()
.min(0)
.max(100)
z.boolean()
z.date()
.or(z.string())
z.enum(['active', 'inactive'])
z.nativeEnum(MyEnum)
z.array(z.string())
.min(1)
.max(10)
z.string().optional()
z.string().nullish()
z.object({
name: z.string(),
age: z.number()
})
PaginationSchema.extend({
keyword: z.string()
})
z.union([z.string(), z.number()])
z.discriminator('type', {
type1: Type1Schema,
type2: Type2Schema
})
Meta 字段说明
z.string().meta({
example: 'value',
description: '字段说明'
})
TypeScript 类型导出
export const UserSchema = z.object({
id: z.string(),
name: z.string()
});
export type userType = z.infer<typeof UserSchema>;
export type UserType = z.infer<typeof UserSchema>;
参考资源
项目内示例
- API Schema 示例:
/Volumes/code/fastgpt-pro/FastGPT/packages/global/openapi/core/app/log/api.ts
- API 实现示例:
/Volumes/code/fastgpt-pro/FastGPT/projects/app/src/pages/api/core/app/logs/list.ts
- 分页 Schema:
packages/global/openapi/api.ts
相关文档
- Zod 官方文档: https://zod.dev/
- FastGPT API 规范:
.claude/skills/pr-review/fastgpt-style-guide.md
- PR Review 审查维度:
.claude/skills/pr-review/code-quality-standards.md
Version: 1.0
Last Updated: 2026-01-27
Maintainer: FastGPT Development Team