考虑对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首页(如下图)。

在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先生!我已经修改了有关突变部分的描述!