javascript - GraphQL 能否在解析器中选择性地解析给定查询结果的字段?

标签 javascript ecmascript-6 graphql

我有以下 REST 端点:

/orders/{id}

returns {
    orderId,
    orderItem,
    customerId
}

/customers/{id}

returns {
   customerId,
   firstName,
   lastName
}

我受限于这两个端点,它们将被包装在我的 graphql 模式中。

我想要以下架构:

type Order {
  orderId: ID!,
  orderItem: String,
  customer: Customer
}

type Customer{
  customerId: ID!
  firstName: String!
  lastName: String!
}

type Query {
  getOrder(id: String!): Order,
  getCustomer(id: String!): Customer
}

我想知道是否可以让 GraphQL 解析 Order 类型中的 Customer 对象?我了解您不能将查询结果传递给另一个查询的参数。

我认为 getOrder 的解析器是:

const getOrderResolver = axios.get(`/orders/${id}`)
  .then((ordersRes) => {
    let customerId;
    if(ordersRes.data.customerId !== null) {
      customerId = ordersRes.data.customerId 
      axios.get(`/customers/${customerId}`)
      .then((customerRes) => ({
        return {
          orderId: ordersRes.data.orderId
          orderItem: ordersRes.data.orderItem
          customer: {
            customerId: customerRes.data.customerId
            firstName: customerRes.data.firstName
            lastName: customerRes.data.lastName 
          }
        }
      })
    } else {
      return {
          orderId: ordersRes.data.orderId
          orderItem: ordersRes.data.orderItem
          customer: null
      }
    }
    })
  })

getCustomer 解析器

const getCustomerResolver = axios.get(`/customers/${customerId}`)
          .then((customerRes) => ({
            return {
                customerId: customerRes.data.customerId
                firstName: customerRes.data.firstName
                lastName: customerRes.data.lastName 
            }
          })

在我的解决方案中,无论是否在 getOrder 查询中查询,始终获取 Customer 类型都会产生额外成本。是否可以重写我的 GraphQL 架构,使 GraphQL 仅在查询时能够解析 Customer 类型?

我给定的 ORDERS REST API 的局限性只返回 CustomerId 使得它很难在 getOrder 中解析,因为 客户 API 需要一个customerId

最佳答案

这里有两点要记住:

  • 除非请求,否则 GraphQL 不会解析字段(即,除非该字段实际包含在请求中,否则不会调用您的解析器)。
  • 每个解析器都可以访问其“父”字段解析到的值。

因此您的 getOrder 解析器只能担心返回一个订单对象:

const resolvers = {
  Query: {
    getOrder: (parent, args, context, info) => {
      const response = await axios.get(`/orders/${args.id}`)
      return response.data
    },
    ...
  },
  ...
}

请注意,如果 REST 端点以与您的字段类型相同的“形状”返回响应,则无需在此处将响应数据映射到您的实际字段——只需返回 response.data .

现在我们可以为订单类型的 customer 字段添加一个解析器:

const resolvers = {
  Query: { ... },
  Order: {
    customer: (parent, args, context, info) => {
      if (!parent.customerId) {
        return null
      }
      const response = await axios.get('/customers/${parent.customerId}')
      return response.data
    },
  },
  ...
}

我们的父字段是 getOrder(或任何其他具有 Order 类型的字段)。 parent 的值将是您在该字段的解析器中返回的任何值(或者如果您返回一个 Promise,则无论 Promise 解析为什么)。因此我们可以使用 parent.customerId 来调用 /customers 端点并从响应中返回数据。同样,只有在实际请求 customer 字段时才会调用此解析器。

关于javascript - GraphQL 能否在解析器中选择性地解析给定查询结果的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56171092/

相关文章:

javascript - "document is not defined"使用具有外部库依赖项的 Jasmine 导入 ES6 (Babel)

graphql - 如何在一个突变中创建嵌套节点?

javascript - 当我使用 Apollo 时,对象数组转换为对象的对象

graphql - 我应该如何解决 Graphite 烯中带有前导下划线的字段?

javascript - Babel 无法正确扩展 Array?

javascript - CasperJS 测试器模块输出到 csv 而不是命令行

javascript - K-combinator (Kestrel) 在 javascript 中的实际使用

javascript - 在 Node.js 循环中等待 Promise,然后再进入下一个迭代

reactjs - 将状态从子组件传递到父组件

javascript - 使用带有固定位置标题的 scrollIntoView