/api-design-safety
当设计或修改 REST API 响应结构、处理 API 返回值时触发。防止 API 设计缺陷导致的字段错位、类型歧义等问题。
$ npx -y skills add doccker/cc-use-exp --skill api-design-safety --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/api-design-safety
Context preview
The summary Claude sees to decide when to auto-load this skill.
当设计或修改 REST API 响应结构、处理 API 返回值时触发。防止 API 设计缺陷导致的字段错位、类型歧义等问题。
SKILL.md
api-design-safety.SKILL.mdname: api-design-safety
description: 当设计或修改 REST API 响应结构、处理 API 返回值时触发。防止 API 设计缺陷导致的字段错位、类型歧义等问题。
API 设计安全规范
当设计或修改 REST API 响应结构时,防止常见的设计缺陷。
---
陷阱 #1: 泛型方法重载歧义
**场景**: 返回类型为 String 时,Java 重载解析可能匹配错误的方法
问题根因
Java 方法重载解析时,`String` 类型参数会优先匹配 `success(String message)` 而非 `success(T data)`,导致数据进入错误的字段。
错误示例
// ApiResponse 有两个重载:
public static <T> ApiResponse<T> success(T data)
public static <T> ApiResponse<T> success(String message, T data)
// ❌ 错误: String 类型匹配到 success(String message)
String avatarUrl = "http://example.com/avatar.jpg";
return ApiResponse.success(avatarUrl);
// 结果: {"code":200, "message":"http://...", "data":null}
// 前端 data.data 拿到 null,导致功能异常正确做法
// ✅ 方案1: 明确指定 message 参数(推荐)
return ApiResponse.success("上传成功", avatarUrl);
// 结果: {"code":200, "message":"上传成功", "data":"http://..."}
// ✅ 方案2: 使用泛型明确类型
return ApiResponse.<String>success(avatarUrl);
// ✅ 方案3: 包装为 DTO(复杂场景推荐)
return ApiResponse.success(new UploadResult(avatarUrl));检查清单
- [ ] 返回 String 类型时,是否明确指定 message 参数
- [ ] 是否有单参数和双参数的重载方法
- [ ] 前端是否正确解析 `data` 字段(而非 `message`)
- [ ] 是否有单元测试验证响应结构
---
陷阱 #2: 响应字段语义不清
**场景**: `message` 和 `data` 字段职责混淆
规范
| 字段 | 用途 | 类型 | 示例 | |------|------|------|------| | `code` | 业务状态码 | int | 200, 400, 500 | | `message` | 用户可读的提示信息 | String | "上传成功", "参数错误" | | `data` | 业务数据 | T | `{"url": "..."}`, `[...]` | | `timestamp` | 响应时间戳 | String | ISO 8601 格式 |
错误示例
// ❌ 错误: 把业务数据放在 message
return ApiResponse.success("avatars/2026-04/xxx.jpeg");
// ❌ 错误: message 包含技术细节
return ApiResponse.error("NullPointerException at line 42");正确做法
// ✅ message 是用户提示,data 是业务数据
return ApiResponse.success("上传成功", avatarUrl);
// ✅ 错误信息对用户友好
return ApiResponse.error("文件格式不支持,请上传 JPG/PNG 格式");---
陷阱 #3: 空值处理不一致
**场景**: 无数据时返回 `null`、`{}`、`[]` 不统一
规范
| 场景 | 推荐返回 | 说明 | |------|---------|------| | 单个对象不存在 | `data: null` | 前端判断 `if (!data)` | | 列表为空 | `data: []` | 前端可直接遍历 | | 分页数据为空 | `data: {list: [], total: 0}` | 保持结构一致 |
错误示例
// ❌ 错误: 有时返回 null,有时返回空对象
if (user == null) {
return ApiResponse.success(null); // 不一致
}
return ApiResponse.success(new UserVO());正确做法
// ✅ 统一返回 null 表示不存在
if (user == null) {
return ApiResponse.success(null);
}
return ApiResponse.success(userVO);
// ✅ 列表统一返回空数组
List<UserVO> users = userService.list();
return ApiResponse.success(users); // 永远不返回 null---
陷阱 #4: HTTP 状态码与业务状态码混淆
**场景**: 业务失败时返回 HTTP 500
规范
| 场景 | HTTP 状态码 | 业务 code | 说明 | |------|------------|----------|------| | 成功 | 200 | 200 | 正常响应 | | 参数错误 | 200 | 400 | 业务层校验失败 | | 未授权 | 401 | - | 认证失败 | | 无权限 | 403 | - | 授权失败 | | 资源不存在 | 200 | 404 | 业务资源不存在 | | 服务器错误 | 500 | - | 代码异常 |
错误示例
// ❌ 错误: 业务失败返回 HTTP 500
if (user == null) {
throw new RuntimeException("用户不存在"); // HTTP 500
}正确做法
// ✅ 业务失败返回 HTTP 200 + 业务 code
if (user == null) {
return ApiResponse.error(404, "用户不存在"); // HTTP 200
}
// ✅ 只有代码异常才返回 HTTP 500
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<?>> handleException(Exception e) {
log.error("服务器错误", e);
return ResponseEntity.status(500)
.body(ApiResponse.error("服务器错误,请稍后重试"));
}---
检查清单(API 设计)
**返回值设计**:
- [ ] String 类型返回时,是否明确指定 message 参数
- [ ] `message` 字段是否只包含用户可读的提示信息
- [ ] `data` 字段是否只包含业务数据
- [ ] 空值处理是否统一(null / [] / {})
**状态码设计**:
- [ ] HTTP 状态码是否只用于传输层(200/401/403/500)
- [ ] 业务状态码是否在响应体的 `code` 字段
- [ ] 业务失败是否返回 HTTP 200 + 业务 code
**前后端协议**:
- [ ] 前端是否正确解析 `data` 字段
- [ ] 前端是否处理了 `data: null` 的情况
- [ ] 是否有 API 文档或接口测试
---
适用范围
- Java: Spring Boot REST API
- Go: Gin/Echo REST API
- Node.js: Express/Koa REST API
- Python: FastAPI/Flask REST API
---
规则溯源
> 📋 本回复遵循:`api-design-safety` - API 设计安全规范
Read more
name: api-design-safety description: 当设计或修改 REST API 响应结构、处理 API 返回值时触发。防止 API 设计缺陷导致的字段错位、类型歧义等问题。
API 设计安全规范
当设计或修改 REST API 响应结构时,防止常见的设计缺陷。
---
陷阱 #1: 泛型方法重载歧义
**场景**: 返回类型为 String 时,Java 重载解析可能匹配错误的方法
问题根因
Java 方法重载解析时,`String` 类型参数会优先匹配 `success(String message)` 而非 `success(T data)`,导致数据进入错误的字段。
错误示例
// ApiResponse 有两个重载:
public static <T> ApiResponse<T> success(T data)
public static <T> ApiResponse<T> success(String message, T data)
// ❌ 错误: String 类型匹配到 success(String message)
String avatarUrl = "http://example.com/avatar.jpg";
return ApiResponse.success(avatarUrl);
// 结果: {"code":200, "message":"http://...", "data":null}
// 前端 data.data 拿到 null,导致功能异常正确做法
// ✅ 方案1: 明确指定 message 参数(推荐)
return ApiResponse.success("上传成功", avatarUrl);
// 结果: {"code":200, "message":"上传成功", "data":"http://..."}
// ✅ 方案2: 使用泛型明确类型
return ApiResponse.<String>success(avatarUrl);
// ✅ 方案3: 包装为 DTO(复杂场景推荐)
return ApiResponse.success(new UploadResult(avatarUrl));检查清单
- [ ] 返回 String 类型时,是否明确指定 message 参数
- [ ] 是否有单参数和双参数的重载方法
- [ ] 前端是否正确解析 `data` 字段(而非 `message`)
- [ ] 是否有单元测试验证响应结构
---
陷阱 #2: 响应字段语义不清
**场景**: `message` 和 `data` 字段职责混淆
规范
| 字段 | 用途 | 类型 | 示例 | |------|------|------|------| | `code` | 业务状态码 | int | 200, 400, 500 | | `message` | 用户可读的提示信息 | String | "上传成功", "参数错误" | | `data` | 业务数据 | T | `{"url": "..."}`, `[...]` | | `timestamp` | 响应时间戳 | String | ISO 8601 格式 |
错误示例
// ❌ 错误: 把业务数据放在 message
return ApiResponse.success("avatars/2026-04/xxx.jpeg");
// ❌ 错误: message 包含技术细节
return ApiResponse.error("NullPointerException at line 42");正确做法
// ✅ message 是用户提示,data 是业务数据
return ApiResponse.success("上传成功", avatarUrl);
// ✅ 错误信息对用户友好
return ApiResponse.error("文件格式不支持,请上传 JPG/PNG 格式");---
陷阱 #3: 空值处理不一致
**场景**: 无数据时返回 `null`、`{}`、`[]` 不统一
规范
| 场景 | 推荐返回 | 说明 | |------|---------|------| | 单个对象不存在 | `data: null` | 前端判断 `if (!data)` | | 列表为空 | `data: []` | 前端可直接遍历 | | 分页数据为空 | `data: {list: [], total: 0}` | 保持结构一致 |
错误示例
// ❌ 错误: 有时返回 null,有时返回空对象
if (user == null) {
return ApiResponse.success(null); // 不一致
}
return ApiResponse.success(new UserVO());正确做法
// ✅ 统一返回 null 表示不存在
if (user == null) {
return ApiResponse.success(null);
}
return ApiResponse.success(userVO);
// ✅ 列表统一返回空数组
List<UserVO> users = userService.list();
return ApiResponse.success(users); // 永远不返回 null---
陷阱 #4: HTTP 状态码与业务状态码混淆
**场景**: 业务失败时返回 HTTP 500
规范
| 场景 | HTTP 状态码 | 业务 code | 说明 | |------|------------|----------|------| | 成功 | 200 | 200 | 正常响应 | | 参数错误 | 200 | 400 | 业务层校验失败 | | 未授权 | 401 | - | 认证失败 | | 无权限 | 403 | - | 授权失败 | | 资源不存在 | 200 | 404 | 业务资源不存在 | | 服务器错误 | 500 | - | 代码异常 |
错误示例
// ❌ 错误: 业务失败返回 HTTP 500
if (user == null) {
throw new RuntimeException("用户不存在"); // HTTP 500
}正确做法
// ✅ 业务失败返回 HTTP 200 + 业务 code
if (user == null) {
return ApiResponse.error(404, "用户不存在"); // HTTP 200
}
// ✅ 只有代码异常才返回 HTTP 500
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<?>> handleException(Exception e) {
log.error("服务器错误", e);
return ResponseEntity.status(500)
.body(ApiResponse.error("服务器错误,请稍后重试"));
}---
检查清单(API 设计)
**返回值设计**:
- [ ] String 类型返回时,是否明确指定 message 参数
- [ ] `message` 字段是否只包含用户可读的提示信息
- [ ] `data` 字段是否只包含业务数据
- [ ] 空值处理是否统一(null / [] / {})
**状态码设计**:
- [ ] HTTP 状态码是否只用于传输层(200/401/403/500)
- [ ] 业务状态码是否在响应体的 `code` 字段
- [ ] 业务失败是否返回 HTTP 200 + 业务 code
**前后端协议**:
- [ ] 前端是否正确解析 `data` 字段
- [ ] 前端是否处理了 `data: null` 的情况
- [ ] 是否有 API 文档或接口测试
---
适用范围
- Java: Spring Boot REST API
- Go: Gin/Echo REST API
- Node.js: Express/Koa REST API
- Python: FastAPI/Flask REST API
---
规则溯源
> 📋 本回复遵循:`api-design-safety` - API 设计安全规范
保留你熟悉的 CLI/IDE,让 Claude Code、Gemini CLI、Codex、Cursor、GitHub Copilot 开箱即用 按费力度从低到高,用最少操作获得最大帮助 不是提示词集合,而是一套可维护的 AI 协作配置系统。
Repo: doccker/cc-use-exp
Other skills on cc-use-exp.
- /api-proxy-safety
网关/代理/WAF/CDN 中间件的安全关键词匹配实现规范,防止纯子串匹配误判正常响应内容中的技术术语(如 Cloudflare、502、error)
Open skill - /async-task-pattern
当 API/任务可能执行超过 10 秒(批量数据处理、远程 API 批量调用、全表扫描、跨租户聚合)时触发。防止同步接口被网关 30s 超时切断、用户重复点击触发并发、状态缓存内存泄漏等问题。提供异步任务状态机标准模板。
Open skill - /bash-style
当用户操作 .sh、Dockerfile、Makefile、.yml、.yaml 文件,或在 Markdown 中编写 bash 代码块时触发。提供 Bash 编写规范。
Open skill - /code-quality-principles
当编写新模块、设计接口、重构代码或代码审查时触发。提供经典模块化六原则检查清单(大小适中/调用深度/扇入扇出/边界清晰/作用域内聚/可预测性),适用于 PR/Review/新模块设计场景。
Open skill - /external-system-debugging
涉及浏览器、编辑器、CDN/WAF、IM 平台、操作系统剪贴板、第三方 SaaS 等"外部黑盒系统"的代码编写或 bug 调试时触发。强制先抓真实环境数据再推理,避免连续 2 轮"凭代码推理"的修复 no-op。关键词:粘贴/复制异常、跨平台显示不一致、第三方 API 怪结果、CDN/WAF 拦截、本地复现失败、HTML→MD 转换丢属性。
Open skill - /field-mapping-safety
当重构涉及字段映射(dataIndex、枚举映射、类型转换)时触发。防止字段名推测错误,确保字段映射的正确性。
Open skill

