3. API 设计原则与规范:RESTful vs gRPC 选择、接口版本管理、请求/响应数据结构设计、错误码规范
在授信决策引擎中,API 是业务系统与决策核心之间的“契约”。本章聚焦四个核心设计维度:协议选型、版本演进、数据结构规范与错误码体系。正确的设计能显著降低集成成本,并为后续的低延迟优化奠定基础。
3.1 协议选型:RESTful vs gRPC
授信决策场景对延迟与吞吐有极高要求。RESTful 与 gRPC 各有优劣,选择需结合内部调用与外部开放接口的不同场景。
| 对比维度 | RESTful (HTTP/JSON) | gRPC (HTTP/2 + Protobuf) |
|---|---|---|
| 传输格式 | JSON(文本,可读性强) | Protobuf(二进制,体积小) |
| 序列化性能 | 中等,CPU 开销较高 | 极高,零拷贝 + 预编译 |
| 延迟 | 较高(HTTP/1.1 队头阻塞) | 极低(HTTP/2 多路复用) |
| 浏览器支持 | 原生支持 | 需 gRPC-Web 代理 |
| 接口契约 | OpenAPI / Swagger(文档驱动) | .proto 文件(代码生成驱动) |
| 流式通信 | 仅 Server-Sent Events 或 WebSocket | 原生支持 Server/Client/Bidirectional 流 |
| 适用场景 | 外部开放 API、异构系统集成 | 内部微服务间高频调用、实时决策 |
实践建议:授信决策引擎内部核心链路(规则计算、模型推理)优先采用 gRPC,可降低 40%-60% 的序列化延迟;对外暴露的查询/审批接口保留 RESTful,降低合作伙伴集成门槛。
3.2 接口版本管理策略
授信决策引擎的规则与模型频繁迭代,接口版本管理不当会导致上下游兼容性灾难。推荐采用 URL 路径版本 + 语义化版本号 的组合策略。
3.2.1 版本号规范
- 主版本 (Major):不兼容的 API 变更(如请求结构重写、删除必填字段)。
- 次版本 (Minor):向后兼容的新增功能(如增加可选参数、新增响应字段)。
- 修订版本 (Patch):内部 bug 修复,接口契约不变。
3.2.2 版本标识方式
| 方式 | 示例 | 优点 | 缺点 |
|---|---|---|---|
| URL 路径 | /v1/credit/decision |
直观、易于路由 | URL 冗余 |
| 请求头 | Accept: application/vnd.credit.v2+json |
URL 干净 | 调试不直观 |
| 查询参数 | /credit/decision?version=1 |
实现简单 | 缓存失效困难 |
推荐方案:对外 RESTful 接口使用
/v{major}/credit/decision 路径版本;内部 gRPC 服务在 .proto 文件中通过 package 声明版本,如 package credit.v2;,并利用 protobuf 的向后兼容特性(字段编号不变即可)。
3.3 请求/响应数据结构设计
授信决策请求通常包含客户信息、产品参数、设备指纹等敏感数据。数据结构设计需兼顾 完整性、可扩展性 与 低解析开销。
3.3.1 请求结构规范
// 授信决策请求 (gRPC protobuf 示例)
message CreditDecisionRequest {
string request_id = 1; // 全局唯一请求ID,用于幂等与追踪
string product_code = 2; // 产品编码
CustomerInfo customer = 3; // 客户信息(嵌套消息)
map<string, string> extra_params = 4; // 扩展参数(向后兼容)
int32 timeout_ms = 5; // 单次决策超时控制
}
message CustomerInfo {
string id_number = 1; // 身份证号(SHA256 脱敏)
string mobile = 2; // 手机号
string name = 3; // 姓名
DeviceInfo device = 4; // 设备信息
}
3.3.2 响应结构规范
message CreditDecisionResponse {
string request_id = 1; // 回传请求ID,用于关联
string decision_code = 2; // 决策结果码(如 APPROVED / REJECTED)
int32 credit_limit = 3; // 授信额度(单位:分)
int32 decision_cost_ms = 4; // 决策耗时(毫秒)
repeated DecisionReason reasons = 5; // 决策原因列表
map<string, string> extra_info = 6; // 扩展信息
}
message DecisionReason {
string rule_id = 1; // 触发的规则ID
string reason_code = 2; // 原因码
string reason_desc = 3; // 原因描述
}
避坑指南:避免在请求/响应中使用
oneof 或 any 类型,它们会增加解析分支与延迟抖动。优先使用 map<string, string> 作为扩展字段,保持二进制兼容性。
3.4 错误码规范
统一的错误码体系是 API 可观测性的基石。授信决策引擎的错误码需区分 系统错误、业务错误 与 参数错误。
3.4.1 错误码分类
| 错误码范围 | 类型 | 说明 | 示例 |
|---|---|---|---|
| 1000-1999 | 系统错误 | 服务内部异常、超时、熔断 | 1001 服务超时 |
| 2000-2999 | 参数错误 | 请求格式错误、必填字段缺失 | 2003 身份证号格式错误 |
| 3000-3999 | 业务错误 | 风控拒绝、额度不足、黑名单 | 3001 命中黑名单 |
| 4000-4999 | 鉴权错误 | API Key 无效、签名错误 | 4002 签名过期 |
3.4.2 错误响应结构
// 统一错误响应 (RESTful JSON 示例)
{
"code": 2003,
"message": "身份证号格式错误",
"details": {
"field": "customer.id_number",
"reason": "长度不为18位"
},
"trace_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
3.4.3 错误码设计原则
- 唯一性:每个错误码全局唯一,不重复使用。
- 可扩展:预留区间,避免新错误码打乱分类。
- 可读性:错误消息使用中文描述,便于业务方理解。
- 可追踪:始终携带
trace_id,便于日志关联。
3.5 本章小结
- 协议选型:内部核心链路用 gRPC,外部开放接口用 RESTful,网关层做协议转换。
- 版本管理:URL 路径主版本 + protobuf package 版本,保持向后兼容。
- 数据结构:使用
map<string, string>扩展字段,避免oneof/any类型。 - 错误码:按系统/参数/业务/鉴权分类,统一响应结构,携带 trace_id。