You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何扩展远程GraphQL Schema,添加带id参数的Persons字段?

如何扩展导入的远程GraphQL Schema(JavaScript方案)

当然可以扩展你导入的远程Schema!用GraphQL生态里的Schema Stitching技术就能轻松实现给Persons字段添加id参数、返回单个Person的需求。下面是具体的实现步骤和代码示例:

1. 获取并包装远程Schema

首先我们需要把远程的Schema导入到本地,这里用introspection的方式获取远程Schema的结构,再包装成可在本地调用的Schema:

const { fetch } = require('cross-fetch');
const { buildClientSchema, introspectionQuery } = require('graphql');
const { wrapSchema, introspectSchema } = require('@graphql-tools/wrap');
const { stitchSchemas } = require('@graphql-tools/stitch');

// 替换成你的远程GraphQL服务器地址
const REMOTE_GQL_URL = 'https://your-remote-server.com/graphql';

async function getWrappedRemoteSchema() {
  // 通过introspection获取远程Schema的元数据
  const introspectionResponse = await fetch(REMOTE_GQL_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query: introspectionQuery }),
  }).then(res => res.json());

  // 构建远程Schema对象
  const rawRemoteSchema = buildClientSchema(introspectionResponse.data);

  // 包装远程Schema,让我们能在本地调用它的字段
  return wrapSchema({
    schema: rawRemoteSchema,
    executor: async ({ document, variables }) => {
      const response = await fetch(REMOTE_GQL_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ query: document, variables }),
      });
      return response.json();
    },
  });
}

2. 定义扩展Schema与Resolver

接下来创建一个扩展Schema,给Persons字段添加id参数,同时编写Resolver处理新参数的逻辑——调用远程的全量Persons接口,再过滤出匹配id的Person:

const { makeExecutableSchema } = require('@graphql-tools/schema');

// 扩展的Schema定义:给Query下的Persons添加id参数,返回单个Person类型
const extensionTypeDefs = `
  extend type Query {
    Persons(id: ID!): Person
  }
`;

// 扩展的Resolver逻辑
const extensionResolvers = {
  Query: {
    Persons: async (_, { id }, context) => {
      // 调用远程Schema的全量Persons接口
      const remoteData = await context.remoteExecutor({
        query: `
          query FetchAllPersons {
            Persons {
              id
              name
              email
              # 这里列出你需要的所有Person字段
            }
          }
        `,
      });

      // 从全量数据中过滤出匹配id的单个Person
      return remoteData.data.Persons.find(person => person.id === id);
    },
  },
};

// 创建可执行的扩展Schema
const extensionSchema = makeExecutableSchema({
  typeDefs: extensionTypeDefs,
  resolvers: extensionResolvers,
});

3. 合并远程Schema与扩展Schema

用stitchSchemas把两个Schema合并,这样你的服务器就会同时支持两种调用方式:

  • 无参数的Persons:返回全部Person数据
  • 带id参数的Persons(id: "123"):返回单个匹配的Person
async function buildCombinedSchema() {
  const remoteSchema = await getWrappedRemoteSchema();
  
  return stitchSchemas({
    subschemas: [
      {
        schema: remoteSchema,
        // 给扩展Resolver提供调用远程Schema的方法
        context: ({ req }) => ({
          remoteExecutor: async ({ query, variables }) => {
            const response = await fetch(REMOTE_GQL_URL, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ query, variables }),
            });
            return response.json();
          },
        }),
      },
      extensionSchema,
    ],
  });
}

4. 启动本地GraphQL服务器(以Apollo Server为例)

最后用Apollo Server托管合并后的Schema,就可以对外提供服务了:

const { ApolloServer } = require('apollo-server');

async function startServer() {
  const combinedSchema = await buildCombinedSchema();
  
  const server = new ApolloServer({
    schema: combinedSchema,
  });

  const { url } = await server.listen({ port: 4000 });
  console.log(`本地GraphQL服务器已启动:${url}`);
}

startServer();

性能优化提示

上面的方案是先获取全量Person再过滤,如果你觉得这种方式性能不佳,可以检查下远程Schema是否有隐藏的单个Person查询字段(比如Person(id: ID!))。如果有的话,直接在Resolver里调用这个字段会更高效,不用拉取全量数据。

另外,如果你希望带id参数时返回的还是数组类型(只包含单个匹配元素),只需要把扩展SDL里的返回类型改成[Person],Resolver里返回[remoteData.data.Persons.find(...)]即可。


内容的提问来源于stack exchange,提问作者Muhammad Kashif Nazar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:23:13