セマンティック・ヌラビリティ
実験的機能: 厳密なセマンティック・ヌラビリティはまだ開発中であるため、Relayにおける実装と動作は変更される可能性があり、この概念とその影響についてさらに理解を深めるにつれて予期せぬ動作が発生する可能性があります。
動機
GraphQLの強みの1つは、フィールド単位のエラー処理が可能で、レスポンスの堅牢性を大幅に向上できることです。しかし、現在のエラー処理はフィールドのヌラビリティに依存しており、そのためベストプラクティスとして推奨されているように、すべてのフィールドをデフォルトでヌラブルにすることが重要です。これにより、最大の堅牢性を確保するには、クライアント開発者がコンポーネント内でフィールドのヌラビリティのあらゆる組み合わせを手動で処理する必要があるというトレードオフが生じます。@required
は多少役立ちますが、最終的には非常に大雑把なツールです。
提案された解決策
セマンティック・ヌラビリティは、GraphQL仕様におけるエラー処理とヌラビリティの分離を目指した初期のGraphQL仕様提案であり、最大の堅牢性を確保しながらも、フィールドの「セマンティック・ヌラビリティ」(サーバー上の実際のレゾルバー関数/メソッドのヌラビリティ)をクライアントに公開することを目的としています。
この提案では、スキーマで「エラー時のみnull」という新しい種類のヌラビリティを指定できるようにします。クライアントがこの種類を見つけており、かつフィールドエラーを帯域外で処理する何らかの戦略を持っている場合、ユーザーコードに公開されるフィールドを非ヌラブルとして扱うことができます。
完全な仕様変更には、GraphQLのスキーマ定義言語に新しい構文を追加する必要がある可能性がありますが、その間、さまざまなGraphQLサーバーとクライアントが、このアイデアを試すために一時的なディレクティブ@semanticNonNull
で協力しています。
簡単に言うと、スキーマのフィールドに@semanticNonNull
を追加して、セマンティックな意味では非ヌラブルであることを示すことができますが、クライアントは引き続きエラー処理の準備をする必要があります。
Relayはスキーマ内の@semanticNonNull
ディレクティブを検索し、@throwOnFieldError
ディレクティブを追加してクエリまたはフラグメントのクライアントサイドエラー処理を有効にしている場合、それらのフィールドに対して非ヌラブルなFlow/TypeScript型を生成します。
たとえば、サーバーがユーザーの名前に対してエラーの場合を除いてnullを返すことがない場合(レゾルバーが非ヌラブル型として型付けされているため)、スキーマのそのフィールドに@semanticNonNull
を適用できます。
directive @semanticNonNull(levels: [Int] = [0]) on FIELD_DEFINITION
type User {
name: String @semanticNonNull
}
ディレクティブをスキーマに追加したら、フラグメントとクエリに@throwOnFieldError
を追加して、フラグメントが読み取られる際にフィールドエラーが発生した場合にクライアントがエラーをスローすることを示します。
Reactのエラーバウンダリを、@throwOnFieldError
を使用しているコンポーネントの上位に必ず追加してください。
以下の例では、Relayによって生成されたuser.name
のTypeScriptまたはFlow型は非ヌラブルになります。
Relayがuser.name
のフィールドエラーを受信した場合、useFragment
はエラーをスローします。このため、これらのエラーをキャッチするための適切なReactエラーバウンダリが配置されていることを確認することが重要です。
import type {UserComponent_user$key} from 'UserComponent_user.graphql';
const React = require('React');
const {graphql, useFragment} = require('react-relay');
type Props = {
user: UserComponent_user$key,
};
function UserComponent(props: Props) {
const user = useFragment(
graphql`
fragment UserComponent_user on User @throwOnFieldError {
name # Will be typed as non-nullable
}
`,
props.user,
);
return <div>{user.name}</div>
}
例
実践的な例として、この例題プロジェクトを参照してください。このプロジェクトでは、Gratsとともに@semanticNonNull
と@throwOnFieldError
を使用するようにRelayが設定されています。Gratsは実験的な@semanticNonNull
ディレクティブを含むスキーマを自動的に導出する機能を備えています。