从graphql中的两个非相干源解析到同一对象

从graphql中的两个非相干源解析到同一对象,graphql,apollo-client,Graphql,Apollo Client,我有一个问题,我不知道如何妥善解决 我正在从事一个项目,我们使用graphql服务器与不同的API进行通信。这些API很旧,很难更新,所以我们决定使用graphql来简化通信 目前,有两个API允许我获取用户数据。我知道这是不连贯的,但遗憾的是,我不能改变任何东西,我需要使用这两个不同的行动。因此,为了简单起见,我想从我的前端应用程序中抽象出它,因此它只要求用户数据,始终采用相同的格式,无论这些数据来自哪个api 只有一个api,graphql的解析器系统帮助很大。但是,当我从第二个api访问用

我有一个问题,我不知道如何妥善解决

我正在从事一个项目,我们使用graphql服务器与不同的API进行通信。这些API很旧,很难更新,所以我们决定使用graphql来简化通信

目前,有两个API允许我获取用户数据。我知道这是不连贯的,但遗憾的是,我不能改变任何东西,我需要使用这两个不同的行动。因此,为了简单起见,我想从我的前端应用程序中抽象出它,因此它只要求用户数据,始终采用相同的格式,无论这些数据来自哪个api

只有一个api,graphql的解析器系统帮助很大。但是,当我从第二个api访问用户数据时,我发现总是很难将相同的对象发送回我的首页。这两个API虽然数据基本相同,但响应格式不同。所以在我的解析器中,根据数据的来源,我应该做这样或那样的事情

例如:

API A 

type User {
   id: string,
   communication: Communication
}

type Communication {
   mail: string,
}
我听说过一些关于阿波罗联盟的事情,但我不能在我们系统的每个api前面都放一个graphql服务器,所以我有点迷茫,当数据来自两个不同的来源时,我如何才能实现前端应用程序的透明性

如果有人已经遇到了同样的问题,或者对我可以做的事情提出了建议,我很高兴:)

无论REST API返回什么,您都需要确定用户类型的“形状”对您的客户端应用程序有意义。对于本例,假设我们使用:

type User {
  id: String
  mail: String
}
此外,在本例中,假设有一个
getUser
字段返回单个用户。任何参数都与场景无关,所以我在这里省略它们

type Query {
  getUser: User
}
假设我不知道要为用户查询哪个API,那么我们的
getUser
解析器可能如下所示:

async () => {
  const [userFromA, userFromB] = await Promise.all([
    fetchUserFromA(),
    fetchUserFromB(),
  ])

  // transform response
  if (userFromA) {
    const { id, communication: { mail } } = userFromA
    return {
      id,
      mail,
    }
  }

  // response from B is already in the correct "shape", so just return it
  if (userFromB) {
    return userFromB
  }
}
type User {
  id: String
  details: UserDetails
}

type UserDetails {
  email: String
}
或者,我们可以使用单个字段解析器来实现相同的效果。例如:

const resolvers = {
  Query: {
    getUser: async () => {
      const [userFromA, userFromB] = await Promise.all([
        fetchUserFromA(),
        fetchUserFromB(),
      ])
      return userFromA || userFromB
    },
  },
  User: {
    mail: (user) => {
      if (user.communication) {
        return user.communication.mail
      }
      return user.mail
    }
  }, 
}
请注意,您不必将模式与现有REST端点的响应匹配。例如,您可能希望返回如下用户:

async () => {
  const [userFromA, userFromB] = await Promise.all([
    fetchUserFromA(),
    fetchUserFromB(),
  ])

  // transform response
  if (userFromA) {
    const { id, communication: { mail } } = userFromA
    return {
      id,
      mail,
    }
  }

  // response from B is already in the correct "shape", so just return it
  if (userFromB) {
    return userFromB
  }
}
type User {
  id: String
  details: UserDetails
}

type UserDetails {
  email: String
}

在这种情况下,您只需将响应从任一API转换为适合您的模式。

谢谢Daniel,因为现在我使用带有
if
的独立fiel解析器,它可以工作,但我想知道是否有更好、更健壮的方法来实现这一点。我的例子在这里非常简单,但实际上它是非常复杂的对象^^并不特别复杂。如果规范化响应很复杂,您可能会发现将响应转换逻辑提取到一个单独的函数中,并在每个返回用户或用户列表的解析器中调用该函数更易于管理和扩展。通过这种方式,您可以避免为用户类型上的各个字段提供解析程序。您也可以使用抽象类型(联合和接口),但创建单独的用户类型并使用抽象类型将它们组合在一起将把处理两个响应之间差异的负担从服务器转移到客户端,这大概不是你想做的。