【问题标题】:GraphQl and Conditional Resolver API RequestsGraphQl 和条件解析器 API 请求
【发布时间】:2020-05-10 14:52:45
【问题描述】:

我不知道如何命名这个问题,但这是我不确定的。

我有一个 React 前端,它正在对我们的 GraphQl 中间层进行 GraphQl 查询,该中间层通过调用我们的旧 REST api 来聚合数据。

例如,在 React 中,我可以调用 getCustomer 查询:

query getCustomer($id: Int!) {
    getCustomer(id: $id) {
      name
      email
  }
}

这将访问 getCustomer 解析器,然后解析器向我们的 REST customers/{id} 端点发出请求以返回我们的数据。

async function getCustomer(_, { id }, ctx) {
  const customer = await ctx.models.customer.getCustomer(id);
  return customer;
}

如果我要打印客户列表,则此请求很好。但是我的问题是如何根据我正在查询的数据在解析器中发出条件 API 请求?

假设每个客户可以有多个地址,并且这些地址位于不同的端点上。我很想在我的前端获得这样的地址:

query getCustomer($id: Int!) {
    getCustomer(id: $id) {
      name
      email
      address {
        city
      }
  }
}

我的解析器如何根据我的typesschemas 处理这个问题?基本上是这样的:

async function getCustomer(_, { id }, ctx) {
  const customer = await ctx.models.customer.getCustomer(id);

  [If the query includes the address field]
    const addresses = await ctx.models.customer.getAddressesByCustomer(id);
    customer.addresses = addresses;
  [/If]

  return customer;
}

最终,目标是让getCustomer 解析器能够根据查询中发送的字段跨多个端点返回所有客户数据,但不会发出那些额外的 API 请求,如果未请求字段。

【问题讨论】:

  • 你用的是什么graphql库?
  • 我们正在运行一个内部客户端来处理 GraphQl 请求 - 所以不使用 Relay 或 Apollo。
  • 你有一个info 对象作为ctx 后面的第四个参数吗?
  • 我们没有。但我注意到文档中提到了info。这可能是我进一步研究的事情吗?

标签: reactjs rest graphql


【解决方案1】:

实际上有两种方法可以做到这一点。第一个依赖于 GraphQL 如何执行请求。只有在以下情况下才会调用字段的解析器:1)“父”字段不为空,并且 2)实际请求了相关字段。这意味着我们可以显式地为地址字段提供解析器:

const resolvers = {
  Customer: {
    addresses: () => {
      return ctx.models.customer.getAddressesByCustomer(id)
    },
  },
}

这样,解析器就会被调用来处理类似的查询

{
  query getCustomer($id: Int!) {
    getCustomer(id: $id) {
      name
      address {
        city
      }
    }
  }
}

但不会被要求

{
  query getCustomer($id: Int!) {
    getCustomer(id: $id) {
      name
    }
  }
}

这种方法在包装简单的 REST API 时效果很好。但是,某些 REST API 允许您通过可选参数请求相关资源。同样,如果您要从数据库中提取数据,您可以将其他表连接到您的查询中。最终结果是以更少的往返次数获得更多的数据。在这种情况下,您将在根级别(在getCustomer 解析器内)进行所有获取。但是,您需要确定自定义实际请求的字段。为此,您需要parse the resolve info object,这是传递给每个解析器的第四个参数。一旦确定实际请求了哪些字段,就可以对 URL 或 SQL 查询进行适当的更改。

【讨论】:

  • 这非常有用。但是我缺少的一个连接是当我查询address 时,该字段如何映射到解析器中的addresseses?这是我需要遵循的命名约定还是什么?
  • 这只是示例代码——如果您的字段名为address,那么resolvers 映射应该反映这一点。我不知道在返回数组时命名字段 address 是否有意义,但这是您的架构:)
  • 谢谢。是的,这是很多伪代码,但我希望它能够正常工作。非常感谢!
【解决方案2】:

您的解析器应如下所示:

const resolvers = {
  Query: {
    getCustomer(id) {
      // return customer object
    }
  },
  Customer: {
    addresses(customer) {
      // return addresses of the customer
    }
  }
}

graphql 服务器将负责调用适当的解析器。

如果您以务实的方式定义架构,则可以在定义字段的同时定义解析器。

【讨论】:

    【解决方案3】:

    Apollo 检查/了解哪些字段已填写,以及需要额外询问的内容。 它调用一个(主要的、顶级的)解析器(用于返回 f.e. 姓名和电子邮件)并在返回的对象不包含所需数据(字段/子项/相关)时调用其他解析器。

    快速解决方法:使用 [the power of] ctx info 参数检查需要哪些字段。

    【讨论】:

    • 为什么执行上下文会包含有关所请求字段的任何信息?
    • @DanielRearden 你是对的,记错了,没有检查 ;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-09
    • 1970-01-01
    • 2018-09-21
    • 2021-05-02
    • 2018-06-08
    • 1970-01-01
    相关资源
    最近更新 更多