如何在GraphQL联邦架构中获取物料的区域特定库存信息?
GraphQL联邦架构中库存字段上下文匹配问题
当前架构定义
1. 区域服务(Zone Service)
扩展Material类型并关联区域,类型定义:
extend type Material @key(fields: "id") { id: ID! @external } type Zone @key(fields: "id") { id: ID! name: String! materials: [Material!]! } type Query { zones: [Zone!]! }
2. 物料服务(Material Service)
提供物料基础信息:
type Material @key(fields: "id") { id: ID! name: String! } type Query { materials: [Material!]! }
3. 库存服务(Stock Service)
扩展Material类型添加库存字段,库存数据关联物料ID和区域ID:
extend type Material @key(fields: "id") { id: ID! @external stocks: Stock! } type Stock { amount: Int! } type Query { stocks: [Stock!]! }
库存数据集:
const stocks = [ { id: "1", zoneId: "1", materialId: "1", amount: 100 }, { id: "2", zoneId: "1", materialId: "2", amount: 50 }, { id: "3", zoneId: "2", materialId: "2", amount: 80 }, { id: "4", zoneId: "2", materialId: "3", amount: 120 }, ];
查询需求与问题
执行以下查询时,期望每个区域下的物料返回对应区域的库存数据:
query Zones { zones { id name materials { id name stocks { amount } } } }
问题:库存字段未结合区域ID(zoneId)返回匹配数据,比如区域B中物料Gravel的库存应为80,但实际返回了50(属于区域A的库存)。
解决方案
核心问题是当前Material.stocks字段仅能获取物料ID,无法拿到当前所在的区域上下文,需通过调整架构传递区域ID信息来解决:
方案1:通过实体扩展传递区域上下文
- 修改Zone Service的Material扩展,新增
zoneId字段传递当前区域ID:
extend type Material @key(fields: "id") { id: ID! @external zoneId: ID! @external # 添加该字段,传递区域上下文 } type Zone @key(fields: "id") { id: ID! name: String! materials: [Material!]! # 该字段的resolver需为每个Material注入zoneId }
- 修改Stock Service的Material扩展,声明依赖
zoneId字段解析库存:
extend type Material @key(fields: "id") { id: ID! @external zoneId: ID! @external # 接收Zone服务传递的区域ID stocks: Stock! @requires(fields: "zoneId") # 声明需要zoneId字段 } type Stock { amount: Int! }
- 在Stock服务的
stocksresolver中,同时用物料ID和区域ID过滤数据:
// Stock服务的resolver示例 const resolvers = { Material: { stocks: (material) => { return stocks.find(stock => stock.materialId === material.id && stock.zoneId === material.zoneId ); } } };
方案2:重新设计实体关联(贴合业务语义)
如果库存本身是区域与物料的关联实体,可定义中间实体明确三者关系:
- 在Zone Service中定义
ZoneMaterial实体:
type ZoneMaterial @key(fields: "zoneId materialId") { zoneId: ID! materialId: ID! material: Material! @external stock: Stock! } type Zone @key(fields: "id") { id: ID! name: String! zoneMaterials: [ZoneMaterial!]! }
- Stock服务扩展
ZoneMaterial实体提供库存数据:
extend type ZoneMaterial @key(fields: "zoneId materialId") { zoneId: ID! @external materialId: ID! @external stock: Stock! } type Stock { amount: Int! }
这种方式更清晰表达“区域-物料-库存”的关联关系,查询时可直接通过zoneMaterials获取对应维度的库存。
关键说明
- GraphQL联邦中,实体字段的解析依赖父级传递的上下文数据,多维度过滤时需确保所需上下文字段(如zoneId)能通过实体扩展传递到对应服务。
@requires指令用于声明解析字段依赖的外部字段,网关会自动收集并传递这些字段给对应服务的resolver。
内容的提问来源于stack exchange,提问作者Krister Johansson
相关产品推荐
相关产品推荐

