GraphQL の Interface と Union - AWS AppSync

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

GraphQL の Interface と Union

GraphQL 型システムは Interfaceをサポートしています。インターフェイスを実装するためにタイプに含める必要がある、フィールドの特定セットをインターフェイスで公開します。

GraphQL 型システムはUnionもサポートしています。Union はインターフェイスと同じです。異なるのはフィールドの共通セットを定義しない点です。Union は、可能なタイプが論理階層を共有しないとき、一般的にインターフェイスより優先されます。

次のセクションは、スキーマの型付けに関するリファレンスです。

インターフェースの例

たとえば、何らかのアクティビティまたは人の集まりを Event インターフェイスで表すことができます。考えられるイベントタイプにはConcertConferenceFestival などがあります。このようなタイプにはすべて、共通の特性 (名前、イベントの開催場所、開始日および終了日など) があります。これらのタイプに差分もあります。Conference には、講演者やワークショップのリストがあり、Concert には演奏するバンドが記載されています。

スキーマ定義言語 (SDL) では、Event インターフェイスは次のように定義されます。

interface Event { id: ID! name : String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int }

また、Event インターフェイスを実装する各タイプは次のようになります。

type Concert implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performingBand: String } type Festival implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performers: [String] } type Conference implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int speakers: [String] workshops: [String] }

インターフェイスは数種類の要素がある場合を表すのに便利です。たとえば、特定の会場で開催されているすべてのイベントを検索できます。次のように findEventsByVenue フィールドをスキーマに追加します。

schema { query: Query } type Query { # Retrieve Events at a specific Venue findEventsAtVenue(venueId: ID!): [Event] } type Venue { id: ID! name: String address: String maxOccupancy: Int } type Concert implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performingBand: String } interface Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int } type Festival implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performers: [String] } type Conference implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int speakers: [String] workshops: [String] }

findEventsByVenueEvent のリストを返します。GraphQL インターフェイスフィールドはすべての実装タイプに共通しているため、Event インターフェイス (idnamestartsAtendsAtvenue、および minAgeRestriction) の任意のフィールドを選択できます。さらに、GraphQL の フラグメントを使用して、タイプを指定している限り、任意の実装タイプのフィールドにアクセスできます。

インターフェイスを使用する GraphQL クエリの例を詳しく見てみましょう。

query { findEventsAtVenue(venueId: "Madison Square Garden") { id name minAgeRestriction startsAt ... on Festival { performers } ... on Concert { performingBand } ... on Conference { speakers workshops } } }

上記のクエリは、結果の単一のリストを生み出し、サーバーで、デフォルトでは、開始日によりイベントをソートできます。

{ "data": { "findEventsAtVenue": [ { "id": "Festival-2", "name": "Festival 2", "minAgeRestriction": 21, "startsAt": "2018-10-05T14:48:00.000Z", "performers": [ "The Singers", "The Screamers" ] }, { "id": "Concert-3", "name": "Concert 3", "minAgeRestriction": 18, "startsAt": "2018-10-07T14:48:00.000Z", "performingBand": "The Jumpers" }, { "id": "Conference-4", "name": "Conference 4", "minAgeRestriction": null, "startsAt": "2018-10-09T14:48:00.000Z", "speakers": [ "The Storytellers" ], "workshops": [ "Writing", "Reading" ] } ] } }

結果はイベントの 1 つのコレクションとして返されるため、共通特性を表すためにインターフェイスを使用すると、結果のソートに大変役立ちます。

ユニオンの例

先に述べたように、ユニオンは共通のフィールドセットを定義しません。検索結果で多様なタイプを表すことがあります。Event スキーマを使用して、次のように SearchResult ユニオンを定義できます。

type Query { # Retrieve Events at a specific Venue findEventsAtVenue(venueId: ID!): [Event] # Search across all content search(query: String!): [SearchResult] } union SearchResult = Conference | Festival | Concert | Venue

この場合、SearchResult ユニオンで任意のフィールドをクエリするには、フラグメントを使用する必要があります。

query { search(query: "Madison") { ... on Venue { id name address } ... on Festival { id name performers } ... on Concert { id name performingBand } ... on Conference { speakers workshops } } }

AWS AppSync でのタイプ解決

タイプ解決は、GraphQL エンジンが特定のオブジェクトタイプとして解決された値を識別するメカニズムです。

ユニオン検索例に戻り、クエリで結果を出した場合、結果リストの各項目は、定義された SearchResult ユニオンの可能なタイプの 1 つ (つまり、ConferenceFestivalConcert、または Venue) として、それ自体を示す必要があります。

FestivalVenueConference から識別するロジックは、アプリケーションの要件に依存するため、GraphQL エンジンには、そのままの結果から可能なタイプを識別するヒントを与える必要があります。

AWS AppSync では、このヒントは __typename という名前のメタフィールドで表されます。その値は、特定されたオブジェクトタイプ名に対応しています。戻り値の型がインターフェイスまたはユニオンに対して __typename が必要です。

タイプ解決の例

前のスキーマを再利用します。コンソールに移動して、[スキーマ] ページで以下を追加することで、手順どおりに進めることができます。

schema { query: Query } type Query { # Retrieve Events at a specific Venue findEventsAtVenue(venueId: ID!): [Event] # Search across all content search(query: String!): [SearchResult] } union SearchResult = Conference | Festival | Concert | Venue type Venue { id: ID! name: String! address: String maxOccupancy: Int } interface Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int } type Festival implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performers: [String] } type Conference implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int speakers: [String] workshops: [String] } type Concert implements Event { id: ID! name: String! startsAt: String endsAt: String venue: Venue minAgeRestriction: Int performingBand: String }

リゾルバーを Query.search フィールドにアタッチしましょう。Resolvers セクションで、[アタッチ] を選択し、NONE タイプの新しいデータソースを作成してから、StubDataSource という名前を付けます。この例では、外部ソースから結果を取得したものとし、リクエストマッピングテンプレートで取得された結果をハードコードします。

リクエストマッピングテンプレートペインで、次のように入力します。

{ "version" : "2018-05-29", "payload": ## We are effectively mocking our search results for this example [ { "id": "Venue-1", "name": "Venue 1", "address": "2121 7th Ave, Seattle, WA 98121", "maxOccupancy": 1000 }, { "id": "Festival-2", "name": "Festival 2", "performers": ["The Singers", "The Screamers"] }, { "id": "Concert-3", "name": "Concert 3", "performingBand": "The Jumpers" }, { "id": "Conference-4", "name": "Conference 4", "speakers": ["The Storytellers"], "workshops": ["Writing", "Reading"] } ] }

アプリケーションが、id フィールドの一部としてタイプ名を返す場合、タイプ解決ロジックは、id フィールドを解析してタイプ名を抽出し、__typename フィールドを各結果を追加します。次のようにレスポンスマッピングテンプレートでそのロジックを実行できます。

注記

Lambda データソースを使用している場合は、このタスクを Lambda 関数の一部として実行することもできます。

#foreach ($result in $context.result) ## Extract type name from the id field. #set( $typeName = $result.id.split("-")[0] ) #set( $ignore = $result.put("__typename", $typeName)) #end $util.toJson($context.result)

次のクエリを実行します。

query { search(query: "Madison") { ... on Venue { id name address } ... on Festival { id name performers } ... on Concert { id name performingBand } ... on Conference { speakers workshops } } }

クエリにより、次の結果が返されます。

{ "data": { "search": [ { "id": "Venue-1", "name": "Venue 1", "address": "2121 7th Ave, Seattle, WA 98121" }, { "id": "Festival-2", "name": "Festival 2", "performers": [ "The Singers", "The Screamers" ] }, { "id": "Concert-3", "name": "Concert 3", "performingBand": "The Jumpers" }, { "speakers": [ "The Storytellers" ], "workshops": [ "Writing", "Reading" ] } ] } }

タイプ解決ロジックはアプリケーションによって異なります。たとえば、特定のフィールドまたはフィールドの組み合わせの存在をチェックする、異なる識別ロジックがあってもかまいません。つまり、performers フィールドの存在を検出して、Festival を識別する、または speakersworkshops フィールドの組み合わせを検出して、Conference を識別できます。最終的に、使用するロジックを定義するのはユーザーです。