繁体   English   中英

结合多个 rest 调用以在 apollo-server 中填充 1 个 graphQL 类型的最佳实践

[英]Best practise to combine multiple rest calls to populate 1 graphQL type in apollo-server

我有 graphql 用户类型,需要来自多个 REST api 和不同服务器的信息。 基本示例:从 rest 域 1 获取用户名,从 rest 域 2 获取用户名。两个 rest 域都有一个共同的“userID”属性。

我的解析器代码 atm 的一个简单示例:

user: async (_source, args, { dataSources }) => {
  try {
    const datasource1 = await dataSources.RESTAPI1.getUser(args.id);
    const datasource2 = await dataSources.RESTAPI2.getUser(args.id);

    return { ...datasource1, ...datasource2 };
  } catch (error) {
    console.log("An error occurred.", error);
  }
  return [];
}

这适用于这个简单的版本,但我对这个解决方案有两个问题:首先,IRL 有很多逻辑要合并 2 个 json 结果。 由于某些字段是共享的,但具有不同的数据(或为空)。 所以这就像挑选两个结果来创建一个组合结果。

我的第二个问题是这仍然是一种瀑布方法。 首先从restapi1获取数据,完成后调用restapi2。 基本上 apollo-server 正在重新引入 rest-waterfall-fetch graphql 试图解决。

牢记这两个问题。我可以优化这段代码还是重写是为了更好的性能或可读性? 或者是否有任何可能有助于这种行为的软件包?

非常感谢!

关于性能,如果两个调用相互独立,您可以利用Promise.all并行执行它们:

const [dataSource1,dataSource2] = await Promise.all([
  dataSources.RESTAPI1.getUser(args.id),
  dataSources.RESTAPI2.getUser(args.id),
])

我们通常让 GraphQL 的默认解析器逻辑完成繁重的工作,但是如果您发现需要从两个调用中“挑选”数据,您可以在根解析器中返回类似这样的内容:

return { dataSource1, dataSource2 }

然后为每个字段编写解析器:

const resolvers = {
  User: {
    someField: ({ dataSource1, dataSource2 }) => {
      return dataSource1.a || dataSource2.b
    },
    someOtherField: ({ dataSource1, dataSource2 }) => {
      return someCondition ? dataSource1.foo : dataSource2.bar
    },
  }
}

假设您的user解析器返回type User放弃...

type User {
  id: ID!
  datasource1: RandomType
  datasource1: RandomType
}

您可以为type User的每个字段创建单独的解析器,这可以将user查询的复杂性降低到仅请求的字段。

query {
 user {
  id
  datasource1 {
    ...
  }
 }
}
const resolvers = {
    Query: {
        user: () => {
            return { id: "..." };
        }
    },
    User: {
        datasource1: () => { ... },
        datasource2: () => { ... } // i wont execute
    }
};

datasource1 & datasource2解析器只会在Query.user执行后并行执行。

用于并行调用。

const users = async (_source, args, { dataSources }) => {
  try {
    const promises = [
      dataSources.RESTAPI1,
      dataSources.RESTAPI2
    ].map(({ getUser }) => getUser(args.id));
    const data = await Promise.all(promises);
    return Object.assign({}, ...data);
  } catch (error) {
    console.log("An error occurred.", error);
  }
  return [];
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM