API 契约核心元素:接口标识、请求响应结构、数据模型定义
模块边界一旦划清,两侧便通过 API 契约 建立双向承诺。契约由三个不可分割的元素组成:接口标识(谁在哪儿)、请求响应结构(怎么传、传什么)、数据模型定义(长什么样、有哪些约束)。三者共同构成一次可验证、可测试、可文档化的交互单元。
2.1 接口标识
接口标识是契约的入口,它必须唯一锁定一个操作。在实际落地中,标识由以下维度组合而成:
| 维度 | 说明 | 典型示例 |
|---|---|---|
| 路径 / 资源 | RESTful 资源路径或 RPC 服务名+方法 | /api/v2/orders/{orderId} |
| HTTP 方法 | 操作语义(GET/POST/PUT/DELETE) | PUT |
| 版本标识 | 路径前缀或 Header 中携带 | Accept: application/vnd.company.v2+json |
| 额外作用域 | 地域、租户、环境等 | X-Region: us-east-1 |
实践要点: 接口标识应做到“一眼可读”——不看文档也大致知道这个接口要操作什么资源、用什么动作。避免使用模糊动词加名词的拼接,如
/doProcess 就远不如 /orders/{orderId}/submit 清晰。
2.2 请求响应结构
结构规定了数据如何包装、如何传递、如何结束。常见分层如下:
- Headers:认证令牌、内容类型、跟踪 ID、速率限制指示等。
- Body:业务数据载体,JSON/Protobuf 序列化后传输。
- HTTP 状态码:最简洁的响应语义(200 成功,400 参数错误,500 内部错误)。
- 错误体规范:当状态码非 2xx 时,body 内的结构化错误信息(code/message/details)。
下面是请求和响应的精简契约示例(YAML):
# 请求契约
paths:
/api/v2/orders:
post:
operationId: createOrder
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateOrderRequest'
responses:
'201':
description: 订单创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/OrderResponse'
'400':
description: 参数校验失败
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
2.3 数据模型定义
数据模型是所有结构的基石。它不仅要描述字段类型,还要声明约束、可选性、组合关系。典型建模要素如下:
| 要素 | 作用 | 示例(JSON Schema) |
|---|---|---|
| 类型与格式 | 基础类型 + 扩展格式 | "type": "string", "format": "date-time" |
| 必须/可选 | 标记必填字段 | "required": ["orderId", "amount"] |
| 枚举与约束 | 限定取值范围 | "enum": ["pending", "confirmed"], "minimum": 0 |
| 嵌套与引用 | 避免扁平化,利用 $ref 复用 | "items": {"$ref": "#/definitions/LineItem"} |
建模黄金法则: 数据模型一旦发布,基本只增不减。请在设计阶段就考虑未来扩展:使用
map 结构、预留 extensions 字段、用 oneOf 处理多态。避免在早期就钉死父类继承。
2.4 三元素关系图
下面的 SVG 展示了三个核心元素如何围绕一次完整的 API 交互协同:
常见陷阱: 很多团队过早陷入数据结构细节而忽略接口标识的稳定性——结果接口路径设计粗糙,后期版本迭代时被迫重写所有客户端。务必先稳定标识(尤其是路径和版本策略),再深化请求响应结构,最后填充数据模型。顺序颠倒将导致大规模返工。