关于 api-design
api-design 是面向 AI Agent 的技能,用于指导生产级 REST API 设计,涵盖资源建模、端点语义、数据结构和 OpenAPI 文档。它也涉及分页、版本管理和统一错误处理。
主要功能
- 01资源及关系建模
- 02CRUD 端点与 HTTP 语义
- 03请求和响应结构设计
- 04分页、筛选与排序
- 05版本管理与内容协商
- 06OpenAPI 3.0 文档
适用场景
- 01根据应用领域设计 API
- 02用 OpenAPI 编写端点和结构文档
- 03规划列表筛选与分页
- 04制定 API 版本和错误规范
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ seb1n/ awesome-ai-agent-skills --skill api-design安装后在 Claude Code 中输入/api-design确认已加载。
详细介绍
API 设计
此技能可让 AI Agent 设计达到生产级质量的 RESTful API。Agent 会对资源建模,定义语义正确的端点和 HTTP 方法,选择合适的状态码,实现分页和版本控制策略,并生成 OpenAPI 文档。输出遵循 REST 约束,包括无状态、统一接口和基于资源的 URI。
工作流
-
识别资源及其关系: 分析应用领域,提取作为资源的名词(例如,用户、任务、评论)。梳理资源之间的关系——一对多、多对多,并确定适合采用子资源还是独立集合。避免基于动词的端点;资源应代表实体,而非操作。
-
定义端点和 HTTP 方法: 为每个资源使用正确的 HTTP 方法定义 CRUD 端点。使用 GET 获取资源(安全、幂等),使用 POST 创建资源(非幂等),使用 PUT 完整替换资源(幂等),使用 PATCH 部分更新资源(幂等),使用 DELETE 删除资源(幂等)。当关系紧密时,将子资源嵌套在其父资源下(例如,
/tasks/{id}/comments)。 -
设计请求和响应架构: 为每个端点定义 JSON 请求正文、响应载荷和查询参数。统一使用 snake_case 或 camelCase 字段名。指定必填字段和可选字段、数据类型及验证约束。设计一套适用于所有端点的一致错误响应封装。
-
实现分页、筛选和排序: 为列表端点添加基于游标或偏移量的分页,并使用
limit和offset(或cursor)查询参数。通过查询参数支持筛选(例如,?status=active),并使用sort和order参数进行排序。在响应正文中返回分页元数据,包括总数以及下一页/上一页链接。 -
定义版本控制和内容协商: 选择一种版本控制策略——URI 路径(
/v1/tasks)、查询参数(?version=1)或 Accept 标头(Accept: application/vnd.api.v1+json)。URI 路径版本控制最简单,也最常见。确保同一版本内向后兼容,并记录弃用时间表。 -
生成 OpenAPI 文档: 生成完整的 OpenAPI 3.0 规范,包含路径、架构、安全方案以及请求/响应示例。在响应文档中包含速率限制标头(
X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset)。
支持的技术
- 规范格式: OpenAPI 3.0/3.1、JSON Schema、AsyncAPI(用于事件驱动扩展)
- 框架: Express.js、FastAPI、Django REST Framework、Spring Boot、Rails API
- 文档工具: Swagger UI、Redoc、Stoplight
- 测试: Postman、Insomnia、REST Client(VS Code)、curl
用法
向 Agent 提供应用领域的描述、涉及的实体以及用户需要执行的操作。Agent 将生成端点定义、请求/响应架构和 OpenAPI 规范。你可以通过请求修改特定端点、添加分页或调整错误格式来迭代完善。
示例
示例 1:任务管理 API(OpenAPI 规范片段)
openapi: 3.0.3
info:
title: Task Management API
version: 1.0.0
description: RESTful API for managing tasks and projects.
servers:
- url: https://api.example.com/v1
paths:
/tasks:
get:
summary: List all tasks
parameters:
- name: status
in: query
schema:
type: string
enum: [pending, in_progress, done]
- name: limit
in: query
schema:
type: integer
default: 20
maximum: 100
- name: cursor
in: query
schema:
type: string
responses:
"200":
description: Paginated list of tasks
headers:
X-RateLimit-Limit:
schema:
type: integer
X-RateLimit-Remaining:
schema:
type: integer
content:
application/json:
schema:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/Task"
pagination:
$ref: "#/components/schemas/CursorPagination"
post:
summary: Create a new task
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TaskCreate"
responses:
"201":
description: Task created
content:
application/json:
schema:
$ref: "#/components/schemas/Task"
"422":
description: Validation error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/tasks/{taskId}:
get:
summary: Get a task by ID
parameters:
- name: taskId
in: path
required: true
schema:
type: string
format: uuid
responses:
"200":
description: Task details
"404":
description: Task not found
components:
schemas:
Task:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
description:
type: string
status:
type: string
enum: [pending, in_progress, done]
created_at:
type: string
format: date-time
TaskCreate:
type: object
required: [title]
properties:
title:
type: string
maxLength: 255
description:
type: string
assignee_id:
type: string
format: uuid
CursorPagination:
type: object
properties:
next_cursor:
type: string
nullable: true
has_more:
type: boolean
ErrorResponse:
type: object
properties:
error:
type: object
properties:
code:
type: string
message:
type: string
details:
type: array
items:
type: object
properties:
field:
type: string
reason:
type: string
示例 2:一致的错误响应格式
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed.",
"details": [
{
"field": "title",
"reason": "Title is required and cannot be empty."
},
{
"field": "assignee_id",
"reason": "Must be a valid UUID."
}
],
"request_id": "req_abc123",
"documentation_url": "https://api.example.com/docs/errors#VALIDATION_ERROR"
}
}
所有端点应统一使用以下标准错误代码:
| HTTP 状态 | 错误代码 | 含义 |
|---|---|---|
| 400 | BAD_REQUEST | 请求语法格式错误 |
| 401 | UNAUTHORIZED | 缺少身份验证或身份验证无效 |
| 403 | FORBIDDEN | 已通过身份验证,但权限不足 |
| 404 | NOT_FOUND | 资源不存在 |
| 409 | CONFLICT | 资源状态冲突(例如,重复) |
| 422 | VALIDATION_ERROR | 语义验证失败 |
| 429 | RATE_LIMITED | 请求过多 |
| 500 | INTERNAL_ERROR | 意外的服务端错误 |
最佳实践
- 资源路径使用复数名词(
/tasks,而非/task),并避免在 URI 中使用动词。无法映射到 CRUD 的操作应使用子资源(例如,POST /tasks/{id}/archive)。 - 通过支持 POST 请求中的
Idempotency-Key标头来实现幂等性。PUT 和 DELETE 天然具有幂等性;应清楚说明这一行为。 - 在每个响应中包含限流标头(
X-RateLimit-Limit、X-RateLimit-Remaining、X-RateLimit-Reset),以便客户端自行控制请求速率。 - 在响应中使用 HATEOAS 链接,以便发现 API。适当时,包含
_links,其中提供self、next、prev和相关资源 URI。 - 从第一天起就进行版本控制,即使目前只有 v1。这样可以避免日后进行痛苦的迁移。弃用旧版本时,应使用
Sunset和Deprecation标头。 - 在 201 Created 响应中返回
Location标头,指向新创建的资源 URI。
边缘情况
- 空集合: 返回
200 OK,并附带空的data数组和has_more: false,而不是404。 - 已删除的资源: 对于硬删除的资源,返回
404 Not Found。对于软删除的资源,返回410 Gone,并附带资源删除时间的元数据。 - 并发更新: 使用
ETag和If-Match标头进行乐观并发控制。如果资源自客户端上次获取后已发生变化,则返回412 Precondition Failed。 - 批量操作中的部分失败: 返回
207 Multi-Status,并附带每项的状态码,以便客户端了解哪些项目成功、哪些失败。 - 尾部斜杠: 将
/tasks/和/tasks规范化为由同一个处理程序处理。如果强制使用一种规范形式,则返回301重定向。 - 未知查询参数: 静默忽略未知参数,或返回带有明确说明的
400——选择一种策略并保持一致。