考虑对GraphQL API进行错误处理的方法

你好,我是 @_mogaming。这篇文章是关于DeNA的2018年度圣诞日历活动中的第17天。

首先

这是关于我作为iOS应用、Android应用和GraphQL API开发人员,在团队的Web前端工程师询问GraphQL API错误处理方法时所提出的方针。目前这个方针运作得很好,如果有任何更好的建议,请给予评论。

太长不看

总结起来非常简单。

    • Queryの場合

基本的にエラーは許容する
そのリクエストにおいて必ず必要なフィールドでエラーが起きていないかをチェックする
リストで返ってくるものは、要件に応じて、必要なフィールドでエラーが起きているデータはリストから弾いてエラーにはしない

Mutationの場合

エラーを許容しない
バックエンドのエンジニアと相談して、エラー種別を識別できるようななにかを追加してもらう
REST APIの場合と変わらない形でハンドリングを行う

在中国范围内,仅需要一个选项来用母语对以下内容进行重新表达:

我们团队使用以下工具。

    • サーバーサイド: GraphQL ruby

Webクライアント: ES2015でGraphQL APIクライアントライブラリは未使用
アプリ: 現状Mutationのみなのでクライアントライブラリは未使用

GraphQL是什么?

请参考我在iOSDC 2018上的演讲幻灯片,虽然我很不好意思地自夸一下,但在那里我解释了这个公式,相信您可以从中获取到大体的概念。

iOS × GraphQL的喜悦与困惑

GraphQL的回应

已决定按照以下格式返回。

{
  "data": { ... }, // 取得しようとしたデータ
  "errors": [ ... ] // エラーが発生していた場合のみエラーオブジェクトが配列に入っている
}

因此,如果简单地处理错误,可以按照以下方式进行。

const response = await new GraphQLRequest().send()
if (response.errors) {
  throw new Error(...)
}

然而,若在不重要的领域出现错误,可能无法渲染组件并向用户显示错误页面。尽管这取决于服务需求,但我认为应尽量减少错误页面的显示,并在能渲染的数据范围内避免不一致性。

使用GraphQL API从中获取数据

以下是其特点。

    • 各リクエストにおいて、必要なフィールドのみを取得する

各コンポーネントごとに必要なフィールドは異なるため、リクエストクエリも異なる

1リクエストの中に複数のクエリを含めることができる

あるクエリ(フィールド)は取得に成功して、あるクエリ(フィールド)は失敗するということがあり得る

我注意到了每个组件都需要不同的字段,所以请求查询也会不同。不同的字段需求意味着每个组件都有确定的“必需数据”或“非必需数据”。

假设有一个请求来绘制截至2018年12月16日的Qiita首页(如下图)。

スクリーンショット 2018-12-16 16.43.05.png

在GraphQL API中,您可以使用一个查询轻松获取中央的Feed、右侧的Qiita:Zine最新文章和用户排名。响应的结果可能如下所示。

{
  "data": {
    "trends": {
      "edges": [
        {
          "node": {
            // 中央の一覧の記事に必要なデータ
            "title": "...",
            ...
          }
        }
      ]
    },
    "qiitaZine": {
      ...
    },
    "userRanking": {
      ...
    }
  },
  "errors": ...
}

虽然只是想象,但在这个首页上最重要的数据应该是trends。而其他的qiitaZine和userRanking字段,最坏的情况是即使没有它们,这个界面也能够正常显示。因此,确定这一点后,这个请求中的必需数据将是trends.edges.[INDEX].node.[各种字段]。

错误处理策略 (Cuo4 Wu4 Chu3 Li3 Ce4 Lv4)

根据上述情况,我们决定在每个请求中明确标示必填字段,并且如果缺乏这些数据就将其视为错误,并显示错误界面。另一方面,虽然可以考虑明确非必填字段的方法,但从效率和服务角度考虑,它们并不是核心内容,因此被排除在外。

在我们的团队中应用GraphQL ruby时,错误对象中存在一个名为”path”的字段。具体来说,它的形式如下。在这种情况下,表示在qiitaZine的列表中出现了一个标题错误。很可能是文章的标题是Non-Nullable的,所以节点本身变为了null。

{
  "data": {
    ...,
    "qiitaZine": {
      "edges": [{
        "node": null
      }, {
        "node": {
          "title": "...",
          ...
        }
      }]
    }
  }
  "errors": [
    {
      ...,
      "path": [
        "qiitaZine",
        "edges",
        0,
        "node",
        "title"
      ]
    }
  ]
}

如果在这个请求中的必填字段与这个路径不匹配,我们不会报错。代码本身很简单,通过response.errors.forEach检查路径是否与事先定义的必填字段匹配,如果匹配,则抛出错误。你能理解吗?

在从GraphQL API获取数据的情况下,执行错误处理操作。

使用GraphQL API更新数据。

Mutation的错误处理基本上与上述相同。但是,缺少用于判断错误类型的字段(对于mutation不仅仅如此,我认为对于query也是必要的)。

在我们的团队中,我们向错误对象的字段中添加了”type”。这是为了确定发生错误的原因而添加的字段。客户端将查看该字段并决定错误消息。与后端工程师商讨,看能否添加”type”或”errorCode”等内容似乎是个好主意。

最后

以上所述的内容仅代表我们团队的做法。如果您有任何意见或建议,请随意在评论区或私信我的Twitter上留言。

追加说明

十分感谢您的指正,@bannzai先生!我已经修改了有关突变部分的描述!

广告
将在 10 秒后关闭
bannerAds