我们之前做的商品中心属于基础服务,几乎所有业务都会调用它。
首页要商品名称和主图,商品详情页要完整信息,下单要价格和库存,搜索又只关心类目和标签。
如果给每个业务单独提供接口,接口数量会越来越多,维护成本也会越来越高。
但如果所有人都调用同一个全量接口,又会产生另外一个问题:大量字段根本用不到,却依然要查询、组装、序列化,再通过网络传输给调用方。
所以,我们后来采用了 Option 模式。
接口增加一个 Option 参数,由调用方自己决定需要哪些维度的数据。
例如:
BASE:商品基础信息,如名称、状态、类型、主图等;
PRICE:价格相关数据;
SKU:规格及库存信息;
BRAND:品牌信息;
CATEGORY:类目信息;
IMAGE:图片列表;
ATTRIBUTE:动态属性(EAV);
DESCRIPTION:商品详情;
ALL:返回全部数据。
如果不传,默认返回 BASE。
购物车一般只需要 BASE + PRICE;订单确认页需要 BASE + SKU;搜索服务通常只关心 BASE + CATEGORY;商品详情页则直接传 ALL。
这样,每个调用方只获取自己真正需要的数据,服务端也只查询对应维度的数据,不查、不组装、不返回无用字段。
另外,我们还提供了批量查询能力,不过单次最多支持查询 50 个商品。
原因不是数据库查不出来,而是需要控制一次请求的处理成本。
如果一次查询几十甚至上百个商品,并且每个商品又要加载多个维度的数据,那么服务端的数据组装、对象创建、序列化以及网络传输都会明显增加。限制批量大小,可以保证接口的响应时间和资源消耗始终保持在可控范围内。
还有一个细节,我们返回给调用方的 DTO 使用的是扁平结构,而不是层层嵌套的 JSON。
这样做最大的好处是接入成本低。无论 Java、Go 还是 PHP,都可以直接反序列化成自己的对象,不需要额外解析复杂的数据结构。
Option模式真正解决的,是可以避免接口随着业务增长不断膨胀。
当一个基础服务开始面对越来越多的调用方,而不同业务需要的数据差异越来越大时,与其不断增加新的接口,不如把数据拆成多个维度,把选择权交给调用方。
最终,一个接口就可以支撑十几个甚至几十个业务系统,而每个系统拿到的,都是自己真正需要的数据,不多,也不少。