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,降低合作伙伴集成门槛。
RESTful vs gRPC 协议对比架构图 RESTful (HTTP/1.1 + JSON) 客户端 (浏览器/App/第三方) API 网关 (Nginx/Kong) 授信决策引擎 (REST 适配层) JSON 序列化/反序列化 延迟: 5-15ms (含序列化) gRPC (HTTP/2 + Protobuf) 内部微服务 (决策/模型/数据) gRPC Channel (HTTP/2 多路复用) 授信决策引擎 (gRPC 原生) Protobuf 二进制序列化 延迟: 1-3ms (零拷贝)

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,便于日志关联。
错误码处理流程与分类 API 请求入口 参数校验 (2000-2999) 业务决策 (3000-3999) 系统执行 (1000-1999) 错误码处理原则 • 逐层校验,快速失败 • 业务错误不暴露堆栈 • 系统错误需告警 • 始终携带 trace_id • 错误消息中文可读 • 预留扩展区间

3.5 本章小结

  • 协议选型:内部核心链路用 gRPC,外部开放接口用 RESTful,网关层做协议转换。
  • 版本管理:URL 路径主版本 + protobuf package 版本,保持向后兼容。
  • 数据结构:使用 map<string, string> 扩展字段,避免 oneof/any 类型。
  • 错误码:按系统/参数/业务/鉴权分类,统一响应结构,携带 trace_id。