Note

3年後の自分のために書いています

GraphQL のエラーハンドリングについていろいろ調べた

前提

GraphQL のレスポンスのフォーマットに関するベストプラクティスとして、レスポンスの HTTP ステータスコードは 200 で統一、レスポンスの errors キーにエラーの詳細な情報を持たせる というのがある(公式な仕様ではないが、Apollo Client も graphql-ruby もこれに沿っている)

最初にまとめ

GraphQL のエラーハンドリングにはトップレベルの errors キーにエラー内容を持たせる方法と、 data キーの中にエラー内容を持たせる方法とある。

公式の仕様書には前者の トップレベルの errors キーにエラー内容を持たせる方法のみが載っている

後者は公式の仕様には無いが graphql-ruby に実装されている機能 なので使える。

しかしエラーの type を定義できないと、エラーの詳細が動的に変わりうるということなので、エラーハンドリングをクライアント側で UI として表現する場合は data キーの中に含めた方が堅牢なアプリケーションになる。(トップレベルの errors キーに含める場合も type 定義できれば良いのだけれど)

説明

レスポンスの形式でいうと以下のような感じ。

トップレベルの errors キーにエラー内容を持たせる

{
  "errors": [
    {
      "message": "Can't continue with this query",
      "locations": [
        {
          "line": 2,
          "column": 10
        }
      ],
      "path": ["user", "login"]
    }
  ],
  "data": {
  // 同じレスポンスに data を含めることもできる
  // ...
  }
}

data キーの中にエラー内容を持たせる

{
  "data": {
    "createPost": {
      "post": null,
      "errors": [
        { "message": "Title can't be blank", "path": ["attributes", "title"] },
        { "message": "Body can't be blank", "path": ["attributes", "body"] }
      ]
    }
  }
}

その他

GraphQLにおけるエラーハンドリングの仕方 - ZOZO Technologies TECH BLOG がめっちゃ参考になった。

ちなみに graphql-ruby では 最近の PR でルートの Schema クラスに rescue_from を定義できるようになり、セーフティネット的なエラーハンドリングを実現できるようになった

これ調べてる間に graphql-ruby のドキュメントのリンク切れを見つけて投げた PR、 無事マージされた。