问题描述
在使用 Apollo Federation的 Web 应用开发中,我们常常需要在本地独立的 subgraph 服务上进行开发和测试,同时其余的 API 依然由远程 Federation Gateway 统一管理。
在前端或 subgraph 开发过程中,你往往希望实现:
- 将本地 subgraph 相关的 API 请求代理到本地(开发环境)实例,以便可以快速迭代和调试;
- 其余子服务(subgraph)的请求继续走联邦网关(Federation Gateway),保持和线上一致的数据与行为。
这种混合开发模式,能大大提升开发效率。
解决方案
1. 本地运行客户端并启用 USE_LOCAL_SUBGRAPH
标志
你可以通过引入一个环境变量(例如 USE_LOCAL_SUBGRAPH
),来启用本地开发模式。例如,添加一个新的 npm 脚本:
json
{
"scripts": {
"start:local-subgraph": "bash version.sh && NODE_ENV=development USE_LOCAL_SUBGRAPH=true webpack-dev-server --config ./config/webpack.dev.js --port 4077"
}
}
这个脚本会以开发模式启动前端应用,并设置 USE_LOCAL_SUBGRAPH
环境变量。
2. Apollo Client 配置
该方法的核心在于如何配置 Apollo Client 动态路由 API 请求:
js
const httpLink = new HttpLink({
fetch,
uri: (operation) => {
if (process.env.USE_LOCAL_SUBGRAPH) {
if (operation.getContext().useFederation) {
// 走联邦网关
return `/app/graphql/${operation.operationName}`;
} else {
// 直接转发到本地 subgraph
return `http://localhost:4001/graphql/${operation.operationName}`;
}
} else {
// 其他环境统一走联邦网关
return `/app/graphql/${operation.operationName}`;
}
},
});
关键特性说明:
-
动态 URI 选择
uri
方法会根据环境变量(USE_LOCAL_SUBGRAPH
)和 operation context(useFederation
,自定义标志)动态决定发送 API 请求的目标地址。 -
通过
useFederation
灵活路由查询你可以在 Apollo 的查询/变更操作中,通过 context 字段的
useFederation
标志(类似这样)明确指定路由目标:js// 查询范例 const { data } = useQuery(MY_QUERY, { context: { useFederation: true // 设为 false 即走本地 subgraph } });
useFederation: true
通过远程 Apollo Gateway 发起请求,适用于涉及多个 subgraph 或需联邦聚合的查询。useFederation: false
直接请求本地 subgraph,适合本地单独调试和测试。- (注意:如果在查询中不写 context,
useFederation
默认为 undefined,此时请求将默认走本地 subgraph。)
3. Webpack 配置
要让上述动态路由生效,需要通过 Webpack 的 DefinePlugin 正确注入环境变量:
js
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
USE_LOCAL_SUBGRAPH: JSON.stringify(process.env.USE_LOCAL_SUBGRAPH),
},
});
这样 USE_LOCAL_SUBGRAPH
才能在前端代码中读取到。
总结
上述方案为基于 Apollo Federation 的 GraphQL 应用开发提供了一种灵活高效的本地开发模式。你可以通过环境变量与 context flag(useFederation
),快速、自如地切换本地独立 subgraph 开发和远程联邦环境,带来如下优势:
- 🚀 可独立、快速地迭代你的 subgraph 子服务
- 🚦 其余数据保持与联邦网关和真实环境一致
- 🛡️ 大大减少线上集成时的意外问题