微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Apollo 服务器因部分数据引发多个错误

如何解决Apollo 服务器因部分数据引发多个错误

我已经通过查询实现了 graphql apollo 服务器:

ordeRSSearch{
  name
  orders: {
    id
    name
  }
}

对于不存在数据的订单,我想为具有如下数据的订单抛出未找到错误数据的数组:

   {
    "errors": [{
      "message": "404: Not Found","path": [ "ordeRSSearch","order",1 ],"extensions": { … }
    },{
      "message": "404: Not Found",3 ],"extensions": { … }
    }],"data": “ordeRSSearch”: [ 
      "name": “test”,"orders": [ {
        “id": “2”,name: “test”
    }]
  }

在上面的响应数据中找不到订单 #1 和 #3 和订单#2。

如何在 apollo 服务器中实现这一点。目前,如果我抛出错误查询执行将停止,并返回一个错误data 属性null,如下所示:

{
  "errors": [{
    "message": "404: Not Found","extensions": { … }
  }],"data": null
}

解决方法

有两种广泛的解决方案需要考虑,但我们需要更多地了解您的 graphql 架构。

我假设您的架构如下:

type query {
  ordersSearch: OrdersSearch!
}
type OrdersSearch {
  name: String!
  orders: [Order!]!
}
type Order {
  id: ID!
  name: String!
}

1。对您的架构进行最少的更改

在您的架构中哪些字段被标记为不可为空在这里非常重要。 这是您消息的一部分,让我认为您的架构包含太多“!”。

如果我抛出一个错误,查询执行就会停止,并且返回一个错误,数据属性为空

根据 GraphQL spec here

如果出现错误的字段被声明为非空,则空结果将向上冒泡到下一个可空字段。在这种情况下,错误的路径应包括到发生错误的结果字段的完整路径,即使该字段不存在于响应中。

因此,如果您的 Order.name 字段解析器抛出错误,您的 GraphQL 服务器不能只返回空 name。它既不能返回空 Order。如果您使用 orders 数组的默认解析器,它不会跳过此空顺序,而 [Order!]! 数组将阻止空元素。所有这些都会冒泡到不能为空的 ordersSearch,您将得到 data: null

那你能做什么?

您可以放宽非空约束。例如这个架构:

type OrdersSearch {
  name: String!
  orders: [Order]! # Elements can be null.
}

这将允许以下形式的响应。不完全是你想要的,但足够接近。

    "data": “ordersSearch”: [ 
      "name": “test”,"orders": [
        null,{
          “id": “2”,"name": “test”
        },null
      ]

2.使用 graphql 架构重新设计

当预计会发生某些错误时,并且后端和前端开发人员必须就其含义达成一致时,不使用 GraphQL 错误是有意义的。只是让错误成为架构的一部分!然后你可以定义所有的行为。

这样的模式可以:

type query {
  ordersSearch: OrdersSearch!
}
type OrdersSearch {
  name: String!
  orders: [OrderSearchResult!]!
}
type OrderSearchResult {
  found: Boolean!
  order: Order
  errorCode: OrderSearchResultErrorCode
}
type Order {
  id: ID!
  name: String!
}
enum OrderSearchResultErrorCode {
  PRODUCT_OUT_OF_STOCK
  PRODUCT_NOT_FOUND
}
,

所以我想我明白你现在在寻找什么。听起来您拥有的对象存在,但您也在进行“一些查找”以查看它是否“完整”或“准备好”或类似的东西。这意味着您有“一些数据”可以返回,并且您想在有部分数据时告诉客户。

TLDR

只要您的解析器返回一个 Promise 数组,而不是单个 Promise,它就会按照您的要求工作。

问题:一个错误

对于这个例子,它只返回一个承诺:

const resolvers = {
  Query: {
    orders: async () => {
      const orderIds = await checkForOrders();

      // Wait for all promises to resolve,and then return the single value
      const orders = await Promise.all(orderIds.map(async(orderId) => {
        return await loadOrder(orderId); // Assume this can throw
      }));
      return orders;
    },},};

响应如下:

{
  "errors": [
    {
      "message": "Order not found: 4adeaca9-81d5-482a-a846-2c09dabfde16","path": ["orders"]
    }
  ],"data": {
    "orders": null
  }
}

解决方案:Promise 数组

现在,如果我更改解析器,使其返回一组承诺,而不仅仅是一个承诺:

const resolvers = {
  Query: {
    orders: async () => {
      const orderIds = await checkForOrders();

      // Return the array of promises
      return orderIds.map(async(orderId) => {
        return await loadOrder(orderId); // Assume this can throw
      });
    },};

回复为您提供了您要查找的内容:

{
  "errors": [
    {
      "message": "Order not found: 4adeaca9-81d5-482a-a846-2c09dabfde16","path": ["orders",1]
    },{
      "message": "Order not found: 8507aaf3-bfc2-46cb-bee2-358847cc632a",2]
    }
  ],"data": {
    "orders": [
      {
        "id": "f18e7627-9844-4927-8441-e61f660b72fd","name": "some name"
      },null,{
        "id": "8af5089c-fa87-4c37-af0b-ce3b79aea6fc","name": "some other name"
      }
    ]
  }
}

编辑:

我意识到这不是完全你所要求的,因为我的回复中有一些 null 值,你的只有成功,但你真的只能得到一个错误一个对象是预期的(并变成 null)。

如果您真的真的想过滤掉那些 null 值,您可以将 formatResponse 中的一个函数传递给 ApolloServer 并将其删除。请注意,如果您这样做,path 值在语义上将不再为真。在我的例子中,我在数字 1 和 2 上抛出了错误,如果我要去掉 null 值,我的数组将只有 [0,1],而 [1] 将有一个值在其中,因此表示我的条目 1 和 2 错误的 path 字符串可能会导致智能 GraphQL 客户端出现问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。