api-development
This skill establishes standardized practices for developing Next.js API routes in FastGPT, emphasizing the use of Zod schemas to define and validate request and response parameters, declaring API route information in file headers, and generating corresponding OpenAPI documentation. Use this when creating new API routes, modifying existing API parameters, defining API types, or reviewing API-related code to ensure consistency, type safety, and complete documentation across the FastGPT project.
git clone --depth 1 https://github.com/labring/FastGPT /tmp/api-development && cp -r /tmp/api-development/.agents/skills/system/api-development ~/.claude/skills/api-developmentSKILL.md
# FastGPT API 开发规范
> FastGPT 项目 API 路由开发的标准化指南,确保 API 的一致性、类型安全和文档完整性。
## 何时使用此技能
- 开发新的 Next.js API 路由
- 修改现有 API 的入参或出参
- 需要 API 类型定义和文档
- 审查 API 相关代码
## 核心原则
### 🔴 必须遵守的规则
1. **API 中实际存在的业务入参和业务出参必须使用 zod schema 定义;无入参或空成功响应不创建空 Schema**
2. **已定义的 schema 必须导出对应的 TypeScript 类型**
3. **必须在 schema 文件头部声明 API 信息(路由、方法、描述、标签),一次性管理员升级/清洗能力除外**
4. **实际存在的入参必须使用 `parseApiInput` 验证;完全无入参时不做空 Query/Body Schema 校验**
5. **实际存在业务数据的函数返回值必须使用 schema.parse() 验证;空成功响应直接返回 `undefined`,不做空 Schema 校验**
6. **必须编写完整的 OpenAPI 文档,一次性管理员升级/清洗能力除外**
### 管理员升级与清洗能力的文档豁免
仅供系统管理员执行、用于一次性升级、迁移、修复或数据清洗的内部接口和脚本,不属于产品 API,不要求:
- 在 `packages/global/openapi/` 声明接口文档;
- 注册 OpenAPI Path;
- 编写 API 头部路由、方法、描述和标签信息。
豁免只针对文档,不豁免安全和校验要求:
- 管理员接口必须使用 `authSystemAdmin` 鉴权;
- 实际存在的 API 入参必须使用 Zod Schema 和 `parseApiInput`,完全无入参时不创建空 Schema;
- 实际存在业务数据的返回值必须使用 Zod Schema 校验,空成功响应直接返回 `undefined`;
- 数据清洗默认使用 dry-run,显式确认后才能写入,并输出成功、跳过和失败统计;
- 清洗逻辑应可重复执行,无法安全修复的数据必须跳过并报告,不得静默填入猜测值。
常规管理员产品接口(例如模型配置 CRUD、用户管理和系统配置)不因仅管理员可用而获得豁免,仍需按标准 API 流程维护文档。
## 开发流程
### 步骤 1: 定义 Zod Schema 并声明 API
**文件位置**: `packages/global/openapi/[module]/[api].ts`
**文件头部必须声明 API 信息**:
```typescript
import { z } from 'zod';
/* ============================================================================
* API: 获取应用对话日志列表
* Route: POST /api/core/app/logs/list
* Method: POST
* Description: 获取指定应用的对话日志列表,支持分页和多种筛选条件
* Tags: ['App', 'Log', 'Read']
* ============================================================================ */
// 入参 Schema
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>;
// 出参 Schema
export const GetAppChatLogsResponseSchema = z.object({
total: z.number().meta({ example: 100, description: '总记录数' }),
list: z.array(ChatLogItemSchema)
});
// 导出出参类型
export type getAppChatLogsResponseType = z.infer<typeof GetAppChatLogsResponseSchema>;
```
**API 声明规范**:
```typescript
/**
* 每个 API 文件必须在文件头部声明以下信息:
*
* 1. API 名称 (API): 简短的功能描述
* 2. 路由 (Route): 完整的 API 路径
* 3. 方法 (Method): HTTP 方法 (GET/POST/PUT/DELETE)
* 4. 描述 (Description): API 的详细功能说明
* 5. 标签 (Tags): API 的分类标签数组
*
* 标签示例:
* - 'App': 应用相关 API
* - 'User': 用户相关 API
* - 'Log': 日志相关 API
* - 'Read': 只读操作
* - 'Write': 写入操作
* - 'Delete': 删除操作
*/
```
**OpenAPI Tag 归属规则**:
- 如果接口能力属于通用模块 A,但会被业务模块 B 使用,则该接口必须同时声明 A 模块 tag 和 B 模块 tag。
- 如果同一个通用接口也被业务模块 C 使用,则继续追加 C 模块 tag。
- 通用模块 tag 表示接口能力和实现抽象归属;业务模块 tag 表示该接口应出现在对应业务文档视角里。
- 如果接口只是业务模块自己的状态查询或状态操作,不属于通用模块能力,则只声明业务模块 tag,不要为了实现位置或相邻目录误加通用模块 tag。
- 示例:`协作者管理` 是通用权限能力,应用协作者接口需要同时声明 `协作者管理` 和应用侧 `权限管理`;`获取应用权限`、`恢复应用继承权限` 是应用自身权限状态接口,只声明应用侧 `权限管理`。
**Schema 定义规范**:
#### ✅ 空入参与空成功响应
- 请求没有 query、body 或 params 时,不要为了形式完整而声明 `z.object({})`,路由中也不需要调用 `parseApiInput`。
- 成功响应没有业务数据时,不要声明 `z.undefined()`、`z.null()` 或 `z.object({})` 作为占位 Schema,也不需要调用 `Schema.parse(undefined)`;handler 直接不返回值或返回 `undefined`。
- 只有请求或响应实际携带业务字段时,才定义对应 Schema、导出类型并在 API 边界执行校验。
- OpenAPI 中无入参接口省略 `requestParams`/`requestBody`;空成功响应只保留状态码和说明,不声明占位 schema。
#### ✅ 字段定义规范
```typescript
// ✅ 好的实践: 完整的 meta 信息
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: '用户状态'
})
});
// ❌ 不好的实践: 缺少 meta 信息
export const GetUserSchemaBad = z.object({
userId: z.string(),
email: z.string(),
age: z.number(),
status: z.string()
});
```
#### ✅ 嵌套对象定义
```typescript
// 嵌套对象应该定义为独立的 Schema
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: '地址信息' })
});
```
#### ✅ 数组定义
```typescript
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: '用户列表' })
});
```
#### ✅ 可选字段
```typescript
export const UpdateUserSchema = z.object({
userId: z.string().meta({ description: '用户 ID' }),
// 可选字段使用 .optional()
name: z.string().optional().meta({ description: '用户名' }),
// 或使用 .nullish() 允许 null 和 undefined
email: z.string().email().nullish().meta({ description: '用户邮箱' })
});
```
#### ✅ 分页 Schema
```typescript
import { PaginationSchema } from '@fastgpt/global/openapi/api';
// 继承分页 Schema
export const GetUserListSchema = PaginationSchema.extend({
// 添加额外的筛选字段
keyword: z.string().optional().meta({ description: '搜索关键词' }),
status: z.enum(['active', 'inactive']).optional().meta({ description: '状态筛选' })
});
```
分页请求参数必须优先复用 `@fastgpt/global/openapi/api` 导出的 `PaginationSchema`,不要在业务域或单个接口中重复声明同构的分页 Schema(例如再次定义 `UserPaginationBodySchema`)。如果接口确实需要额外筛选条件,使用 `PaginationSchema.extend(...)`;只有存在明确的兼容性或协议差异时,才允许定义专用 wrapper,并在附近说明原因。分页响应优先复用 `PaginationResponseSchema`。
#### ✅ 多个 API 的 Schema 文件
```typescript
/* ============================================================================
* API: 获取日志键
*Expert prompt engineering skill that transforms Claude into "Alpha-Prompt" - a master prompt engineer who collaboratively crafts high-quality prompts through flexible dialogue. Activates when user asks to "optimize prompt", "improve system instruction", "enhance AI instruction", or mentions prompt engineering tasks.
当用户需要弃用一个工作流节点(保留向后兼容、隐藏出模板面板)时触发该 skill。FastGPT 工作流节点的弃用流程标准化封装,覆盖模板、Dispatcher、UI 引用等所有需要改动的位置。
将 FastGPT 文档从中文翻译为面向北美用户的英文。当用户提到翻译文档、i18n、国际化、translate docs、新增/修改了中文文档需要同步英文版时,使用此 skill。也适用于用户要求检查文档翻译缺失、批量翻译、或对比中英文文档差异的场景。
为 FastGPT 新资源接入权限管理。当用户需要为新资源(如 AgentSkill、Plugin 等)添加权限支持时触发。
仅当用户明确手动指定使用 pr-review skill 时触发;不要因为用户传入 PR 链接、要求 review 或要求代码审查而自动触发。
当用户需要编写一个单元测试时,触发该 skill,编写单元测试。
手动触发的 FastGPT PR 或本地分支变更梳理技能。仅当用户显式调用 $pr-change-analysis 时使用;用于 reviewer 分析一个 GitHub PR 或当前本地分支相对 upstream/main 的需求变更、影响范围、代码质量与代码风格,不用于自动审查触发。
FastGPT CI workflow 双轨同步。当用户修改或新增 .github/workflows/ 下的 GitHub Actions workflow 时必须触发:同步更新 .forgejo/workflows/ 对应文件保持功能一致,或判断是否需要新建 Forgejo 版本。涉及 CI、GitHub Actions、Forgejo Actions、镜像构建、container registry、artifact、workflow yaml 改动、build-* workflow、test-* workflow 时也使用此技能。即使用户只提到"改一下 CI"或"加个 workflow"也应触发。