Apollo Federation中如何跨子图校验输入字段并获取外部服务数据
解决方案
分两种常用实现路径,都可以满足你的需求:
方案1:直接调用Location服务的公开查询接口(最简单直接)
不需要依赖联邦的特殊能力,直接在Menu服务中封装对Location服务的GraphQL查询调用即可,示例代码如下:
// 需提前在Menu服务内初始化指向Location服务的GraphQL客户端 const { gql } = require('apollo-server') const locationServiceClient = require('./your-location-service-client-init') async storeMenu(_, { location_id }, __, ___) { // 调用Location服务的查询接口获取数据 const { data: { location } } = await locationServiceClient.query({ query: gql` query GetLocation($id: ID!) { location(id: $id) { id name address # 其他你需要使用的Location字段 } } `, variables: { id: location_id } }) // 可按需增加Location合法性校验 if (!location) { throw new Error(`ID为${location_id}的点位不存在`) } // 后续菜单存储逻辑,可直接使用拿到的location对象 const newMenu = await yourDatabaseOperation.save({ location_id, ...otherMenuParams }) return newMenu }
方案2:通过Apollo网关的实体查询接口获取(符合联邦架构最佳实践)
如果你的架构要求所有子服务间调用必须走网关,不想在Menu服务中维护各个子服务的独立地址,可以用联邦原生的_entities实体查询能力:
- 首先在Menu服务的Schema中扩展声明Location实体:
extend type Location @key(fields: "id") { id: ID! @external }
- 之后在resolver中构造实体查询请求发送到Apollo网关即可:
const { gql } = require('apollo-server') const gatewayClient = require('./your-gateway-client-init') async storeMenu(_, { location_id }, __, ___) { const { data: { _entities } } = await gatewayClient.query({ query: gql` query GetLocationEntity($representations: [_Any!]!) { _entities(representations: $representations) { ... on Location { id name address # 其他你需要使用的Location字段 } } } `, variables: { representations: [ { __typename: "Location", id: location_id } ] } }) const location = _entities[0] // 后续业务逻辑和方案1一致 }
补充说明
你提到的@key/@external这类联邦指令确实仅用于对象类型的字段拼接场景,无法直接作用于输入参数实现跨服务数据注入,所有输入参数关联的外部服务数据都需要通过显式的服务调用获取。
内容的提问来源于stack exchange,提问作者Ozal Zarbaliyev
相关产品推荐
相关产品推荐

