NestJS Resolver中mergeInfo不可用,如何实现GraphQL请求代理?
Answer
问题分析
你遇到的核心问题是mergeInfo仅在**Schema Stitching(Schema拼接)**场景下才会被注入到info对象中,而当前你的NestJS GraphQL模块配置没有启用Schema Stitching,所以无法访问info.mergeInfo。下面提供两种可行的解决思路:
方案一:启用Schema Stitching,让mergeInfo可用
要让mergeInfo出现在resolver的info参数里,你需要手动将本地Schema和远程Schema通过Schema Stitching合并,这样GraphQL工具链会自动注入mergeInfo对象。
步骤1:安装依赖
首先安装Schema Stitching所需的工具包:
npm install @graphql-tools/stitch @graphql-tools/schema
步骤2:修改GraphQLModule配置
调整forRootAsync的工厂函数,手动构建并合并本地与远程Schema:
import { stitchSchemas } from '@graphql-tools/stitch'; import { buildSchema } from 'type-graphql'; // 导入你的本地Resolver import { CarResolver } from './car.resolver'; GraphQLModule.forRootAsync({ imports: [CarModule], inject: [CarService], useFactory: async (mainAppService: MainAppService) => { // 构建本地Schema(如果是Code First模式) const localSchema = await buildSchema({ resolvers: [CarResolver], typePaths: ['./**/*.graphql'], }); // 获取你已经定义好的远程Schema const remoteCarSchema = await fetchRemoteSchema(); // 拼接本地与远程Schema const mergedSchema = stitchSchemas({ subschemas: [ { schema: localSchema }, { schema: remoteCarSchema }, ], }); return { context: async ({ req }) => ({ userId: 1 }), definitions: { outputAs: 'interface', path: '../../myschema.gql' }, schema: mergedSchema, // 使用拼接后的Schema }; }, }),
步骤3:正常使用delegateToSchema
现在你的getCar resolver里就能正常访问info.mergeInfo了,原来的代码无需修改即可运行。
方案二:更简便的代理方式——使用wrapSchema
如果不想手动写delegateToSchema逻辑,你可以用wrapSchema直接创建一个可自动代理请求的远程Schema,再和本地Schema合并,无需自定义Resolver。
步骤1:修改远程Schema获取逻辑
更新fetchRemoteSchema函数,返回一个包裹后的Schema:
import { wrapSchema } from '@graphql-tools/wrap'; const fetchRemoteSchema = async (): Promise<GraphQLSchema> => { const http = new HttpLink({ fetch: nodeFetch, uri: process.env.CAR_GRAPHQL_URL }); const link = setContext((_, prevContext) => ({ headers: { Authorization: `Basic ${process.env.CAR_BASIC_AUTH_TOKEN}` }, })).concat(http); const remoteSchema = await introspectSchema(link); // 包裹Schema,自动处理请求代理 return wrapSchema({ schema: remoteSchema, link, // 可选:添加transforms来修改请求(比如参数映射) transforms: [ { transformRequest(request) { // 将context中的userId映射为远程请求的id参数 if (request.operationName === 'car') { return { ...request, variables: { id: request.context.userId }, }; } return request; }, }, ], }); };
步骤2:合并Schema到NestJS配置
在GraphQLModule中合并本地和包裹后的远程Schema:
import { mergeSchemas } from '@graphql-tools/schema'; GraphQLModule.forRootAsync({ imports: [CarModule], inject: [CarService], useFactory: async (mainAppService: MainAppService) => { const localSchema = await buildSchema({ resolvers: [CarResolver], typePaths: ['./**/*.graphql'], }); const remoteCarSchema = await fetchRemoteSchema(); // 合并两个Schema const mergedSchema = mergeSchemas({ schemas: [localSchema, remoteCarSchema], }); return { context: async ({ req }) => ({ userId: 1 }), definitions: { outputAs: 'interface', path: '../../myschema.gql' }, schema: mergedSchema, }; }, }),
优势
这种方式下,如果本地Schema的字段定义和远程一致,你甚至不需要写getCar resolver——合并后的Schema会自动把请求转发到远程服务器,大大简化了代码。
额外建议
- 如果你使用的是NestJS的Code First模式,确保
buildSchema正确导入了你的Resolver和类型。 - 对于多服务的复杂场景,Apollo Federation也是一个可选方案,但需要远程GraphQL服务器支持Federation规范,配置成本相对更高。
内容的提问来源于stack exchange,提问作者Maxim
相关产品推荐
相关产品推荐

