@catch ディレクティブ
@catch ディレクティブは、Relay クエリ/フラグメント/ミューテーションのフィールドに追加して、ランタイムでの例外と予期しない値の処理方法を宣言できます。@catch を使用すると、Relay は null 値(以前のデフォルトの動作)ではなく、レスポンスデータ内の例外を提供できます。
GraphQL レスポンスにフィールドエラーが含まれている場合、Relay はエラーを探し、そのフィールドまたは親フィールドに@catchディレクティブが存在する場合は、{ok: true, value: "あなたの値"}または{ok: false, errors: [...]}で応答します。
エラーが発生したフィールドに直接@catchエラーがキャッチされた場合、エラーはそのフィールドに提供されます。例を以下に示します。
query MyQuery {
  viewer {
    name @catch
    age
  }
}
nameにエラーが含まれている場合、次のようにnameフィールドのレスポンスデータにエラーが提供されます。
{
    viewer: {
        name: {
            ok: false,
            errors: [
                {
                    message: "Couldn't get name",
                    path: ['viewer', 'name']
                }
            ]
        }
        age: 39
    }
}
ただし、フィールドの祖先に@catchが存在する場合は、エラーがそこへバブルアップします。
query MyQuery {
  viewer @catch {
    name
    age
  }
}
{
    viewer: {
        ok: false,
        errors: [
            {
                message: "Couldn't get name",
                path: ['viewer', 'name']
            }
        ]
    }
}
@catchでキャッチできるもの
ペイロードエラー
ペイロードエラーは、特定のフィールドのレスポンスを実行中にサーバー側で例外が発生した結果として発生するエラーです。この場合、GraphQL サーバーは値が存在するべき場所に null 値を提供し、別の errors オブジェクトを提供します。
フィールドで@catchを使用すると、Relay はこれらのエラーをインラインで提供するため、処理が容易になり、非表示になることがなくなります。
もう1つの大きな副作用として、フィールドがNULL許容の場合、null が例外の結果であるか真の null であるかがわかるようになります。これは、形状に値がnullの{ok: true}、または実際のエラーを含む{ok: false}が含まれるためです。
@catchの下の@required(action: THROW)
@catchを含む祖先を持つ@required(action: THROW)がある場合、例外をスローする代わりに、@requiredエラーはバブルアップし、通常のエラーと同じ方法で提供されます。例を以下に示します。
query MyQuery {
  viewer @catch {
    name @required(action: THROW)
    age
  }
}
{
    viewer: {
        ok: false,
        errors: [
            {
                message: "Relay: Missing @required value at path 'viewer.name' in 'MyQuery'.",
            }
        ]
    }
}
レスポンス内のデータの欠落
Relay でデータの欠落が発生する可能性のある例を以下に示します。
フィールドに値があることが期待され、そのフィールドが未定義の場合、そのフィールドは「データが欠落している」と見なされます。これも予期しない状態であり、祖先に@catchがある場合、次のようにキャッチされます。
{
    viewer: {
        ok: false,
        errors: [
            {
                message: "Relay: Missing data for one or more fields in MyQuery",
            }
        ]
    }
}
@catchは@throwOnFieldErrorとどのように連携しますか?
@throwOnFieldErrorを使用すると、フィールドエラーが発生したときにフィールドがJavaScript例外をスローできます。@catchを使用すると、この場合、JavaScript例外を発生させないようにRelayに指示します。代わりに、上記と同じ動作とルール(親フィールドへのバブルアップを含む)で、エラーをデータオブジェクトに提供するように要求します。
@throwOnFieldErrorなしで@catchを使用することもできます。それでも、データオブジェクトにエラーが提供されます。しかし、@catchの下にない他のフィールドは、@throwOnFieldErrorがないため、引き続きスローされません。
@throwOnFieldErrorの詳細については、こちらをご覧ください。
@catch の引数
to: RESULT (デフォルト)
@catch(to: RESULT)は、エラーを含む同じフィールドまたは子フィールドに対してエラーをインラインで提供するという上記の動作を有効にします。これはデフォルトの引数であるため、@catchまたは@catch(to: RESULT)のどちらかを記述しても、動作は同じになります。
to: NULL
@catch(to: NULL)は、@catchが使用可能になる前に存在していたものとまったく同じ動作を提供します。エラーが含まれている場合、フィールドは null になります。