Javascript 组合多个rest调用以在apollo服务器中填充1个graphQL类型的最佳实践

Javascript 组合多个rest调用以在apollo服务器中填充1个graphQL类型的最佳实践,javascript,json,rest,graphql,apollo-server,Javascript,Json,Rest,Graphql,Apollo Server,我的graphql用户类型需要来自多个RESTAPI和不同服务器的信息。 基本示例:从rest域1获取用户名,从rest域2获取lastname。这两个rest域都有一个公共的“userID”属性 我的解析程序代码atm的简化示例: user: async (_source, args, { dataSources }) => { try { const datasource1 = await dataSources.RESTAPI1.getUser(args.id);

我的graphql用户类型需要来自多个RESTAPI和不同服务器的信息。 基本示例:从rest域1获取用户名,从rest域2获取lastname。这两个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服务器基本上重新引入了rest瀑布获取graphql试图解决的问题

记住这两个问题。。我可以优化这段代码,还是重写以获得更好的性能或可读性?或者是否有任何软件包可以帮助实现此行为


非常感谢

假设您的
用户
解析器返回
类型用户
放弃

type User {
  id: ID!
  datasource1: RandomType
  datasource1: RandomType
}
您可以为
类型用户
中的每个字段创建单独的解析程序,这可以将
用户
查询的复杂性降低到仅请求的字段

query {
 user {
  id
  datasource1 {
    ...
  }
 }
}
const解析器={
查询:{
用户:()=>{
返回{id:“…”};
}
},
用户:{
数据源1:()=>{…},
数据源2:()=>{…}//我不会执行
}
};

datasource1
datasource2
解析器将仅在
查询之后并行执行。用户执行

关于性能,如果两个调用彼此独立,您可以利用
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
    },
  }
}
打平行电话

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 [];
};