Skip to content

GraphQL エラーハンドリング戦略 ​

GraphQLのResponse には Payload と Errors がある。このうち Errors の使い方について説明する。

Backendが返す Errors の 型は以下のようになる。

json
{
  "errors": [
    {
      "message": "エラーメッセージ",
      "extensions": {
        "code": "ERROR_CODE",
        "notifyMessage": "ユーザー向けメッセージ"
      }
    }
  ]
}

以下、 code と notifyMessage について説明する

エラーコード(code)について ​

code中身
UNAUTHENTICATED認証されていない
FORBIDDENアクセス権がない
BAD_USER_INPUTユーザー入力が無効
INTERNAL_SERVER_ERRORサーバー内部エラー

エラーメッセージ(notifyMessage)について ​

エラーメッセージは基本的に Backend で定義します。どうしてもフロントエンド側でハンドリングしたい場合は、Payload型に含めてください。

Backend ​

こんな感じで渡します。

go
if ent.IsConstraintError(err) {
    return nil, NewBadUserInputError(err, NewErrorOptions("ユーザー名が既に使用されています"))
}

Frontend ​

基本的にはなにもしなくてOKです。 ただし、mutation でエラーが発生しても、ユーザーにエラーを通知したくないタイミングがあると思います。 その場合は、以下のように対応してください。

Javascript ​

contextでpreventErrorNotifyを渡してください。

javascript
const [updateScenarioMutation] = useMutation(UpdateScenarioDocument, {
    context: {
      preventErrorNotify: true,
    },
  });

Dart ​

mutation に引数preventErrorNotifyを渡せるようにしたのでそれを使ってください。


背景 ​

現状、プロダクトでは主にエラーハンドリング戦略として「パターン2」を採用しています。ValidationエラーはUXの観点から基本的にフロントエンドでやることが望ましいので、GraphQLで明示的に含める必要がなく、この戦略が効率的です。

エラーハンドリングのパターン ​

パターン1: スキーマにエラーを定義 ​

この方法では、すべてのエラーコードがスキーマに定義され、エラーメッセージはフロントエンドで管理されます。

パターン2: GraphQLエラーメッセージを併用 ​

スキーマにエラーは定義されず、バリデーションエラーはGraphQLのエラーメッセージとして返されます。

戦略 ​

デフォルト: パターン2 ​

フロントエンドでは、このエラーメッセージをそのままユーザーに通知します。

特定のケース: パターン1の併用 ​

フロントエンドでのエラーハンドリングが必要な場合、パターン1を併用します。

  • この時、スキーマの変更が必要なので、Backendチームとコミュニケーションを行いながら行います。

考慮すべきポイント ​

  1. 型安全性: パターン1を併用することで、フロントエンドで型安全にエラーを扱うことが可能です。
  2. メンテナンス性: パターン2をデフォルトとすることで、スキーマの肥大化を防ぎます。
  3. ユーザーエクスペリエンス: パターン2で渡されたメッセージをそのままユーザーに通知することで、エラーハンドリングのコストを削減します。