name: api-documentation description: 使用OpenAPI/Swagger规范编写REST API文档,包括端点文档、认证、错误处理和SDK指南。适用于API参考文档、Swagger规范、客户端库文档。触发器:api文档、openapi、swagger、端点文档、rest api、api参考、sdk文档、api规范、文档api、api端点、请求响应示例、模式文档、openapi 3.1、redoc、stoplight、postman集合、api探索器、交互式文档、api契约、api模式、swagger ui、认证流程、速率限制。
API文档
概述
全面的API文档技能,覆盖OpenAPI/Swagger规范、端点文档、认证流程、错误处理、版本控制策略和SDK/客户端文档。结合技术精度和清晰、用户友好的写作,创建开发者实际可用的文档。
指令
1. 首先理解API
- 审查所有端点及其用途
- 识别认证机制
- 理解请求/响应模式
- 注意错误条件和边界情况
- 检查现有API模式的一致性
2. 文档组件
每个API应文档化:
- 认证:如何认证
- 基础URL:环境特定的URL
- 端点:所有可用操作
- 模式:请求/响应模型
- 错误:错误代码和处理
- 速率限制:节流策略
- 版本控制:版本工作原理
最佳实践
技术准确性
- 在整个文档中使用一致的术语
- 使用$ref保持模式DRY
- 文档化所有可能的响应代码
- 验证示例与模式一致性
- 包括适当的JSON模式约束
清晰性和可用性(来自技术写作专长)
- 为开发者受众写作:假设技术能力,跳过居高临下的解释
- 以实用示例开头:展示后再解释
- 使用主动语调和直接语言
- 为每个端点提供可工作的curl示例
- 用完整、可复制的示例解释认证
- 用具体数字和头信息文档化速率限制
- 突出显示常见错误场景
- 包括频繁问题的故障排除提示
交互式文档
- 设计用于自动生成文档(Redoc、Swagger UI、Stoplight)
- 使用operationId进行稳定客户端生成
- 逻辑标记端点以便导航
- 编写在markdown和UI工具中渲染良好的描述
- 包括不同场景的多个请求/响应示例
OpenAPI 3.1 关键特性
完整JSON模式支持
- 使用JSON Schema 2020-12词汇
- 支持const、if/then/else、dependentSchemas
- 原生oneOf/anyOf/allOf与鉴别器
示例处理
- 单一示例:使用
example属性 - 多个示例:使用
examples对象与命名场景 - 示例在模式定义和操作级别中
Webhooks文档
webhooks:
userCreated:
post:
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/UserEvent"
内容协商
content:
application/json:
schema: { ... }
application/xml:
schema: { ... }
text/csv:
schema:
type: string
安全方案
- 多种流程的OAuth2
- OpenID Connect发现
- 相互TLS
- 使用扩展的自定义安全方案
示例
OpenAPI/Swagger规范
openapi: 3.1.0
info:
title: 用户管理API
description: |
管理用户及其配置文件的API。
## 认证
所有端点需要Bearer令牌认证。
通过POST /auth/login获取令牌。
## 速率限制
- 标准:每分钟100个请求
- 认证:每分钟1000个请求
version: 2.0.0
contact:
name: API支持
email: api-support@example.com
url: https://developer.example.com
license:
name: MIT
url: https://opensource.org/licenses/MIT
servers:
- url: https://api.example.com/v2
description: 生产环境
- url: https://api.staging.example.com/v2
description: 预发布环境
- url: http://localhost:3000/v2
description: 本地开发
tags:
- name: 用户
description: 用户管理操作
- name: 认证
description: 认证和授权
security:
- BearerAuth: []
paths:
/users:
get:
summary: 列出所有用户
description: |
检索分页用户列表。
结果按创建日期排序(最新在前)。
operationId: listUsers
tags:
- 用户
parameters:
- $ref: "#/components/parameters/PageParam"
- $ref: "#/components/parameters/LimitParam"
- name: status
in: query
description: 按用户状态过滤
schema:
type: string
enum: [active, inactive, pending]
- name: search
in: query
description: 按姓名或邮箱搜索
schema:
type: string
minLength: 2
responses:
"200":
description: 成功响应
content:
application/json:
schema:
$ref: "#/components/schemas/UserListResponse"
example:
data:
- id: "usr_123"
email: "john@example.com"
name: "John Doe"
status: "active"
createdAt: "2024-01-15T10:30:00Z"
pagination:
page: 1
limit: 20
total: 150
hasMore: true
"401":
$ref: "#/components/responses/Unauthorized"
"429":
$ref: "#/components/responses/RateLimited"
post:
summary: 创建新用户
description: 创建新用户账户
operationId: createUser
tags:
- 用户
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/CreateUserRequest"
examples:
basic:
summary: 基础用户创建
value:
email: "jane@example.com"
name: "Jane Smith"
password: "secureP@ssw0rd"
withRole:
summary: 具有管理员角色的用户
value:
email: "admin@example.com"
name: "Admin User"
password: "secureP@ssw0rd"
role: "admin"
responses:
"201":
description: 用户创建成功
content:
application/json:
schema:
$ref: "#/components/schemas/UserResponse"
"400":
$ref: "#/components/responses/BadRequest"
"409":
description: 具有此邮箱的用户已存在
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "USER_EXISTS"
message: "具有此邮箱的用户已存在"
/users/{userId}:
get:
summary: 按ID获取用户
description: 通过唯一标识符检索特定用户
operationId: getUserById
tags:
- 用户
parameters:
- $ref: "#/components/parameters/UserIdParam"
responses:
"200":
description: 成功响应
content:
application/json:
schema:
$ref: "#/components/schemas/UserResponse"
"404":
$ref: "#/components/responses/NotFound"
patch:
summary: 更新用户
description: 更新用户属性。仅更新提供的字段。
operationId: updateUser
tags:
- 用户
parameters:
- $ref: "#/components/parameters/UserIdParam"
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateUserRequest"
responses:
"200":
description: 用户更新成功
content:
application/json:
schema:
$ref: "#/components/schemas/UserResponse"
"400":
$ref: "#/components/responses/BadRequest"
"404":
$ref: "#/components/responses/NotFound"
delete:
summary: 删除用户
description: 永久删除用户账户
operationId: deleteUser
tags:
- 用户
parameters:
- $ref: "#/components/parameters/UserIdParam"
responses:
"204":
description: 用户删除成功
"404":
$ref: "#/components/responses/NotFound"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
description: |
从POST /auth/login获取的JWT令牌。
在头信息中包含:`Authorization: Bearer <token>`
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
description: 服务器到服务器认证的API密钥
parameters:
UserIdParam:
name: userId
in: path
required: true
description: 唯一用户标识符
schema:
type: string
pattern: "^usr_[a-zA-Z0-9]+$"
example: usr_123abc
PageParam:
name: page
in: query
description: 页码(从1开始)
schema:
type: integer
minimum: 1
default: 1
LimitParam:
name: limit
in: query
description: 每页项目数
schema:
type: integer
minimum: 1
maximum: 100
default: 20
schemas:
User:
type: object
required:
- id
- email
- name
- status
- createdAt
properties:
id:
type: string
description: 唯一标识符
example: usr_123abc
email:
type: string
format: email
description: 用户的邮箱地址
example: john@example.com
name:
type: string
description: 用户全名
example: John Doe
status:
type: string
enum: [active, inactive, pending]
description: 账户状态
role:
type: string
enum: [user, admin, moderator]
default: user
createdAt:
type: string
format: date-time
description: 账户创建时间戳
updatedAt:
type: string
format: date-time
description: 最后更新时间戳
CreateUserRequest:
type: object
required:
- email
- name
- password
properties:
email:
type: string
format: email
name:
type: string
minLength: 2
maxLength: 100
password:
type: string
format: password
minLength: 8
description: 必须包含大写字母、小写字母、数字和特殊字符
role:
type: string
enum: [user, admin, moderator]
default: user
UpdateUserRequest:
type: object
minProperties: 1
properties:
name:
type: string
minLength: 2
maxLength: 100
status:
type: string
enum: [active, inactive]
UserResponse:
type: object
properties:
data:
$ref: "#/components/schemas/User"
UserListResponse:
type: object
properties:
data:
type: array
items:
$ref: "#/components/schemas/User"
pagination:
$ref: "#/components/schemas/Pagination"
Pagination:
type: object
properties:
page:
type: integer
limit:
type: integer
total:
type: integer
hasMore:
type: boolean
Error:
type: object
properties:
error:
type: object
properties:
code:
type: string
description: 机器可读的错误代码
message:
type: string
description: 人类可读的错误消息
details:
type: array
items:
type: object
properties:
field:
type: string
message:
type: string
responses:
BadRequest:
description: 无效请求参数
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "VALIDATION_ERROR"
message: "请求验证失败"
details:
- field: "email"
message: "必须是有效的邮箱地址"
Unauthorized:
description: 需要认证
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "UNAUTHORIZED"
message: "无效或缺少认证令牌"
NotFound:
description: 资源未找到
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "NOT_FOUND"
message: "请求的资源未找到"
RateLimited:
description: 速率限制超出
headers:
X-RateLimit-Limit:
schema:
type: integer
description: 每分钟请求限制
X-RateLimit-Remaining:
schema:
type: integer
description: 剩余请求
X-RateLimit-Reset:
schema:
type: integer
description: 限制重置的Unix时间戳
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
example:
error:
code: "RATE_LIMITED"
message: "请求过多。请在60秒后重试。"
端点文档(Markdown)
## 创建用户
在系统中创建新用户账户。
**端点:** `POST /users`
**认证:** 必需(Bearer令牌)
### 请求
#### 头信息
| 头信息 | 必需 | 描述 |
| ------------- | -------- | ------------------------------------- |
| Authorization | 是 | Bearer令牌 |
| Content-Type | 是 | `application/json` |
| X-Request-Id | 否 | 用于跟踪的唯一请求标识符 |
#### 身体参数
| 参数 | 类型 | 必需 | 描述 |
| --------- | ------ | -------- | ------------------------------------------------------------------------------- |
| email | string | 是 | 有效的邮箱地址 |
| name | string | 是 | 全名(2-100字符) |
| password | string | 是 | 密码(最少8字符,必须包含大写字母、小写字母、数字、特殊字符) |
| role | string | 否 | 用户角色:`user`、`admin`、`moderator`。默认:`user` |
#### 示例请求
\`\`\`bash
curl -X POST https://api.example.com/v2/users \
-H "Authorization: Bearer eyJhbG..." \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"name": "Jane Smith",
"password": "SecureP@ss123"
}'
\`\`\`
### 响应
#### 成功响应(201 Created)
\`\`\`json
{
"data": {
"id": "usr_abc123",
"email": "jane@example.com",
"name": "Jane Smith",
"status": "pending",
"role": "user",
"createdAt": "2024-01-15T10:30:00Z"
}
}
\`\`\`
#### 错误响应
| 状态 | 代码 | 描述 |
| ------ | ---------------- | ------------------------ |
| 400 | VALIDATION_ERROR | 无效请求体 |
| 401 | UNAUTHORIZED | 缺少或无效令牌 |
| 409 | USER_EXISTS | 邮箱已注册 |
| 429 | RATE_LIMITED | 请求过多 |
**400 Bad Request:**
\`\`\`json
{
"error": {
"code": "VALIDATION_ERROR",
"message": "请求验证失败",
"details": [
{
"field": "password",
"message": "密码必须至少8个字符"
}
]
}
}
\`\`\`
认证文档
# 认证
## 概述
API支持两种认证方法:
1. **Bearer令牌(JWT)** - 用于用户面向的应用
2. **API密钥** - 用于服务器到服务器集成
## Bearer令牌认证
### 获取令牌
\`\`\`bash
POST /auth/login
Content-Type: application/json
{
"email": "user@example.com",
"password": "your-password"
}
\`\`\`
**响应:**
\`\`\`json
{
"accessToken": "eyJhbGciOiJIUzI1NiIs...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJl...",
"expiresIn": 3600,
"tokenType": "Bearer"
}
\`\`\`
### 使用令牌
在Authorization头信息中包含令牌:
\`\`\`
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
\`\`\`
### 令牌生命周期
| 令牌 | 生命周期 | 用法 |
| ------------- | -------- | ----------------------- |
| 访问令牌 | 1小时 | API请求 |
| 刷新令牌 | 30天 | 获取新访问令牌 |
### 刷新令牌
\`\`\`bash
POST /auth/refresh
Content-Type: application/json
{
"refreshToken": "dGhpcyBpcyBhIHJlZnJl..."
}
\`\`\`
## API密钥认证
对于服务器到服务器集成,使用API密钥认证。
### 创建API密钥
1. 转到仪表板 > 设置 > API密钥
2. 点击“创建新密钥”
3. 选择权限和过期时间
4. 复制并安全存储密钥
### 使用API密钥
在`X-API-Key`头信息中包含:
\`\`\`
X-API-Key: sk_live_abc123...
\`\`\`
### API密钥最佳实践
- 切勿在客户端代码中暴露密钥
- 定期轮换密钥(每90天)
- 为每个环境使用单独密钥
- 应用最低必需权限
错误响应文档
# 错误处理
## 错误响应格式
所有错误遵循一致格式:
\`\`\`json
{
"error": {
"code": "ERROR_CODE",
"message": "人类可读描述",
"details": [
{
"field": "fieldName",
"message": "字段特定错误"
}
],
"requestId": "req_abc123"
}
}
\`\`\`
## HTTP状态码
| 状态 | 含义 | 何时使用 |
| ------ | ----------------- | --------------------------------------- |
| 200 | OK | 成功的GET、PUT、PATCH |
| 201 | Created | 成功的POST创建资源 |
| 204 | No Content | 成功的DELETE |
| 400 | Bad Request | 无效请求语法或参数 |
| 401 | Unauthorized | 缺少或无效认证 |
| 403 | Forbidden | 有效认证但权限不足 |
| 404 | Not Found | 资源不存在 |
| 409 | Conflict | 资源状态冲突 |
| 422 | Unprocessable | 有效语法但语义错误 |
| 429 | Too Many Requests | 速率限制超出 |
| 500 | Internal Error | 服务器端错误 |
## 常见错误代码
### 认证错误
| 代码 | HTTP状态 | 描述 | 解决方案 |
| ------------------ | ----------- | ---------------------- | ---------------------------- |
| UNAUTHORIZED | 401 | 未提供令牌 | 包含Authorization头 |
| TOKEN_EXPIRED | 401 | 令牌已过期 | 刷新访问令牌 |
| TOKEN_INVALID | 401 | 令牌格式错误 | 获取新令牌 |
| INSUFFICIENT_SCOPE | 403 | 令牌缺少权限 | 请求适当范围 |
### 验证错误
| 代码 | HTTP状态 | 描述 | 解决方案 |
| ---------------- | ----------- | ------------------------- | ----------------------------------- |
| VALIDATION_ERROR | 400 | 请求验证失败 | 检查`details`获取特定字段 |
| INVALID_JSON | 400 | 格式错误的JSON体 | 验证JSON语法 |
| MISSING_FIELD | 400 | 必需字段缺失 | 包括所有必需字段 |
### 资源错误
| 代码 | HTTP状态 | 描述 | 解决方案 |
| --------------- | ----------- | ---------------------- | ---------------------- |
| NOT_FOUND | 404 | 资源不存在 | 验证资源ID |
| ALREADY_EXISTS | 409 | 重复资源 | 使用唯一标识符 |
| RESOURCE_LOCKED | 423 | 资源被锁定 | 等待并重试 |
## 在代码中处理错误
### JavaScript/TypeScript
\`\`\`typescript
try {
const response = await api.createUser(userData);
} catch (error) {
if (error.status === 401) {
await refreshToken();
return retry();
}
if (error.status === 429) {
const retryAfter = error.headers['retry-after'];
await sleep(retryAfter \* 1000);
return retry();
}
if (error.body?.error?.code === 'VALIDATION_ERROR') {
const fieldErrors = error.body.error.details;
displayFieldErrors(fieldErrors);
}
}
\`\`\`
版本控制文档
# API版本控制
## 版本格式
API使用URL路径版本控制:
\`\`\`
https://api.example.com/v{major}/resource
\`\`\`
当前版本:**v2**
## 支持的版本
| 版本 | 状态 | 退役日期 |
| ------- | ---------- | ----------- |
| v2 | 当前 | - |
| v1 | 已弃用 | 2024-12-31 |
## 版本生命周期
1. **当前**:积极开发和支持
2. **已弃用**:支持但不新增功能
3. **退役**:90天的只读访问
4. **已停用**:不再可访问
## 破坏性 vs 非破坏性变更
### 非破坏性(无需版本变更)
- 添加新端点
- 添加可选参数
- 添加新响应字段
- 添加新枚举值
### 破坏性(主版本变更)
- 移除端点
- 移除或重命名字段
- 更改字段类型
- 更改认证方法
- 更改错误格式
## 迁移指南:v1到v2
### 认证变更
**v1:** 查询参数中的API密钥
\`\`\`
GET /v1/users?api_key=abc123
\`\`\`
**v2:** 头信息中的Bearer令牌
\`\`\`
GET /v2/users
Authorization: Bearer eyJhbG...
\`\`\`
### 响应格式变更
**v1:** 扁平响应
\`\`\`json
{
"id": "123",
"name": "John"
}
\`\`\`
**v2:** 包装响应
\`\`\`json
{
"data": {
"id": "usr_123",
"name": "John"
}
}
\`\`\`
SDK文档
# JavaScript SDK
## 安装
\`\`\`bash
npm install @example/api-client
\`\`\`
## 快速开始
\`\`\`javascript
import { ApiClient } from '@example/api-client';
const client = new ApiClient({
apiKey: process.env.API_KEY,
environment: 'production' // 或 'sandbox'
});
// 创建用户
const user = await client.users.create({
email: 'jane@example.com',
name: 'Jane Smith'
});
console.log(user.id); // usr_abc123
\`\`\`
## 配置
\`\`\`javascript
const client = new ApiClient({
// 必需
apiKey: 'sk*live*...',
// 可选
environment: 'production', // 'production' | 'sandbox'
timeout: 30000, // 请求超时(毫秒)
retries: 3, // 自动重试失败请求
logger: console, // 自定义日志器
});
\`\`\`
## 资源
### 用户
\`\`\`javascript
// 分页列出用户
const { data, pagination } = await client.users.list({
page: 1,
limit: 20,
status: 'active'
});
// 获取单个用户
const user = await client.users.get('usr_123');
// 创建用户
const newUser = await client.users.create({
email: 'new@example.com',
name: 'New User'
});
// 更新用户
const updated = await client.users.update('usr_123', {
name: 'Updated Name'
});
// 删除用户
await client.users.delete('usr_123');
\`\`\`
## 错误处理
\`\`\`javascript
import { ApiError, ValidationError, RateLimitError } from '@example/api-client';
try {
await client.users.create({ email: 'invalid' });
} catch (error) {
if (error instanceof ValidationError) {
console.log(error.details); // 字段级别错误
} else if (error instanceof RateLimitError) {
console.log(`请在 ${error.retryAfter} 秒后重试`);
} else if (error instanceof ApiError) {
console.log(error.code, error.message);
}
}
\`\`\`
## TypeScript支持
SDK包含完整的TypeScript定义:
\`\`\`typescript
import { ApiClient, User, CreateUserParams } from '@example/api-client';
const params: CreateUserParams = {
email: 'typed@example.com',
name: 'Typed User'
};
const user: User = await client.users.create(params);
\`\`\`
文档工具
交互式文档生成器
Redoc - 干净的三面板布局,带搜索
npx @redocly/cli build-docs openapi.yaml --output docs.html
Swagger UI - 试用功能,广泛认可
docker run -p 80:8080 -e SWAGGER_JSON=/api/openapi.yaml -v $(pwd):/api swaggerapi/swagger-ui
Stoplight Elements - 可嵌入的Web组件
<script src="https://unpkg.com/@stoplight/elements/web-components.min.js"></script>
<elements-api apiDescriptionUrl="./openapi.yaml" router="hash" />
验证和Linting
Redocly CLI - Lint OpenAPI规范
npx @redocly/cli lint openapi.yaml
npx @redocly/cli bundle openapi.yaml --output bundled.yaml
Spectral - 灵活linting,带自定义规则
spectral lint openapi.yaml --ruleset .spectral.yaml
客户端生成
OpenAPI Generator - 多语言客户端/服务器生成
openapi-generator-cli generate -i openapi.yaml -g typescript-fetch -o ./client
Postman集合导出
npm install -g openapi-to-postmanv2
openapi2postmanv2 -s openapi.yaml -o collection.json
测试和模拟
Prism - 从OpenAPI规范模拟服务器
prism mock openapi.yaml
# 返回规范中的示例响应
Dredd - 根据OpenAPI契约测试API
dredd openapi.yaml http://localhost:3000
文档模式
渐进式披露
从快速开始到高级主题结构化文档:
- 认证快速开始(单一示例)
- 常见用例(食谱)
- 完整端点参考
- 高级主题(webhooks、分页策略)
代码示例策略
- 提供多种语言的示例(curl、JavaScript、Python、Go)
- 使用真实数据(不是foo/bar)
- 展示完整工作示例,不是片段
- 在示例中包含错误处理
API探索器集成
包含“试一试”功能:
- 从环境预填充认证
- 提供示例负载
- 显示实际请求/响应
- 支持环境切换(sandbox/production)
版本控制沟通
- 提前6+个月宣布弃用
- 提供并排比较的迁移指南
- 在API响应中包含弃用头信息
- 维护变更日志,带破坏性/非破坏性标签