リアルタイムデータ - AWS AppSync

リアルタイムデータ

GraphQL スキーマサブスクリプションディレクティブ

AWS AppSync のサブスクリプションはミューテーションに対する応答として呼び出されます。つまり、GraphQL スキーマディレクティブをミューテーションで指定することで、AWS AppSync で任意のデータソースをリアルタイム対応にすることができます。AWS AppSync クライアント SDK は、サブスクリプション接続管理を自動的に処理します。SDK は、クライアントとサービス間のネットワークプロトコルとして、純粋な WebSocket または MQTT over WebSockets のいずれかを使用します。プロトコルは、使用しているクライアントのバージョンによって異なります。

注意: サブスクリプションへの接続時に認可を制御するには、フィールドレベルの認可に対して、IAM、Amazon Cognito ID プール、または Amazon Cognito ユーザープールなどのコントロールを活用できます。サブスクリプションできめ細かなアクセスコントロールを実行する場合、サブスクリプションフィールドにリゾルバーをアタッチし、AWS AppSync データソースと呼び出し元の ID を使用してロジックを実行できます。詳細については、「セキュリティ」を参照してください。

サブスクリプションはミューテーションからトリガーされ、ミューテーション選択セットが受信者に送信されます。

次の例では、GraphQL サブスクリプションの操作方法を示します。データソースを指定しません。これは、データソースが AWS Lambda、Amazon DynamoDB、または Amazon Elasticsearch Service のいずれかであるからです。

サブスクリプションの使用を開始するには、次のようにサブスクリプションのエントリポイントをスキーマに追加する必要があります。

schema { query: Query mutation: Mutation subscription: Subscription }

ブログ投稿サイトを持っており、新しいブログにサブスクライブし、既存のブログに変わるものとします。これを行うには、スキーマに次の Subscription 定義を追加します。

type Subscription { addedPost: Post updatedPost: Post deletedPost: Post }

さらに、次のミューテーションがあるとします。

type Mutation { addPost(id: ID! author: String! title: String content: String url: String): Post! updatePost(id: ID! author: String! title: String content: String url: String ups: Int! downs: Int! expectedVersion: Int!): Post! deletePost(id: ID!): Post! }

通知を受け取る各サブスクリプションに @aws_subscribe(mutations: ["mutation_field_1", "mutation_field_2"]) ディレクティブを追加することで、これらのフィールドをリアルタイム対応にできます。手順は以下のとおりです。

type Subscription { addedPost: Post @aws_subscribe(mutations: ["addPost"]) updatedPost: Post @aws_subscribe(mutations: ["updatePost"]) deletedPost: Post @aws_subscribe(mutations: ["deletePost"]) }

@aws_subscribe(mutations: ["",..,""]) は、ミューテーション入力の配列を受け取るため、サブスクリプションをトリガーする複数のミューテーションを指定できます。クライアントからサブスクライブする場合、GraphQL クエリは次のようになります。

subscription NewPostSub { addedPost { __typename version title content author url } }

上記のサブスクリプションクエリは、クライアント接続とツールに必要です。ただし、MQTT over WebSockets を使用している場合、ミューテーションをトリガーするクライアントは、サブスクライバーが受け取る選択セットを指定します。これを実証するために、別のモバイルクライアントまたはサーバーからミューテーションが行われたとします (たとえば、mutation addPost(...){id author title })。この場合、コンテンツ、バージョン、および URL はサブスクライバーに公開されません。代わりに、ID、作成者、およびタイトルが公開されます。

純粋な WebSocket クライアントを使用する場合、各クライアントが独自の選択セットを定義できるため、選択セットのフィルタリングはクライアントごとに行われます。この場合、サブスクリプション選択セットは、ミューテーション選択セットのサブセットである必要があります。たとえば、ミューテーション addPost(...){id author title url version} にリンクされたサブスクリプション addedPost{author title} は、投稿の作成者とタイトルのみを受け取ります。他のフィールドは受け取りません。ただし、ミューテーションの選択セットに作成者が欠けていた場合、サブスクライバーは作成者フィールドに対して null 値を取得します (または、スキーマ内で作成者フィールドが required/not-null と定義されている場合はエラー)。

さらに、アプリケーションで MQTT over WebSockets を使用している場合は、注意すべき変更点があります。関連付けられたサブスクリプション選択セットを必須フィールドで構成せず、ミューテーションフィールドを使用してサブスクライブされたクライアントにデータをプッシュした場合、純粋な WebSocket に移動すると動作が変わります。上記の例では、選択セットに author フィールドが定義されていないサブスクリプションは、フィールドがミューテーションで定義されているため、MQTT over WebSockets を使用して作成者名を返しますが、純粋な WebSocket に対して同じ動作は適用されません。サブスクリプション選択セットは、純粋な WebSocket を使用する場合に不可欠です。サブスクリプションでフィールドが明示的に定義されていない場合、AWS AppSync によって返されません。

前の例では、サブスクリプションに引数はありませんでした。次のようなスキーマがあるとします。

type Subscription { updatedPost(id:ID! author:String): Post @aws_subscribe(mutations: ["updatePost"]) }

この場合、クライアントでサブスクリプションが次のように定義されます。

subscription UpdatedPostSub { updatedPost(id:"XYZ", author:"ABC") { title content } }

スキーマの subscription フィールドの戻り値の型は、対応する mutation フィールドの戻り値の型に一致する必要があります。前の例では、これが addPostaddedPost の両方が Post タイプとして返され、表示されます。

クライアントでサブスクリプションをセットアップするには、「クライアントアプリの作成」を参照してください。

サブスクリプション引数の使用

GraphQL サブスクリプションを使用するときに重要なのは、引数をいつ、どのように使用するかについて理解することです。細かい変更により、発生したミューテーションをいつどのように通知するのかを変更できます。そのためには、クイックスタートの「サンプルスキーマの起動」セクションで、「イベント」と「コメント」を作成するサンプルスキーマを参照してください。このサンプルスキーマでは、以下のミューテーションが発生します。

type Mutation { createEvent( name: String!, when: String!, where: String!, description: String! ): Event deleteEvent(id: ID!): Event commentOnEvent(eventId: ID!, content: String!, createdAt: String!): Comment }

デフォルトサンプルでは、特定の eventId 引数が渡されるとき、クライアントがコメントにサブスクライブできます。

type Subscription { subscribeToEventComments(eventId: String!): Comment @aws_subscribe(mutations: ["commentOnEvent"]) }

ただし、クライアントで、単一のイベントまたはすべてのイベントのサブスクライブを許可する場合、感嘆符 (!) をサブスクリプションプロトタイプから削除することにより、この引数を省略可能にできます。

subscribeToEventComments(eventId: String): Comment

この変更により、この引数が省略されたクライアントですべてのイベントのコメントを取得します。さらに、クライアントで、すべてのイベントに対するすべてのコメントに明示的にサブスクライブする場合は、次のように引数を削除します。

subscribeToEventComments: Comment

1 つ以上のイベントのコメントに対してこれらを使用します。作成されたすべてのイベントについて知りたい場合は、次のように記述します。

type Subscription { subscribeToNewEvents: Event @aws_subscribe(mutations: ["createEvent"]) }

複数の引数を渡すこともできます。たとえば、特定の場所と時間で、新しいイベントの通知を受け取る場合、次のようにします。

type Subscription { subscribePlaceDate(where: String! when: String!): Event @aws_subscribe(mutations: ["createEvent"]) }

その結果、クライアントアプリケーションは、以下の操作を実行できます。

subscription myplaces { subscribePlaceDate(where: "Seattle" when: "Saturday"){ id name description } }

引数値 null には意味があります。

AWS AppSync でサブスクリプションクエリを作成するとき、引数値 null を使用する場合と、引数を完全に省略する場合とでは、フィルタ処理の結果は異なります。

例で説明しましょう。イベントアプリサンプルに戻って、イベントを作成し、イベントに関するコメントを投稿してみましょう。クイックスタートの「サンプルスキーマの起動」セクションのサンプルスキーマを参照してください。

スキーマを変更して、コメントの送信元を説明する新しい location フィールドを Comment フィールドに追加しましょう。値は座標のセットまたは場所です。以下のスキーマでは、簡潔になるように値は省略しています。

type Comment { # The id of the comment's parent event. eventId: ID! # A unique identifier for the comment. commentId: String! # The comment's content. content: String # Location where the comment was made location: String } type Event { id: ID! name: String where: String when: String description: String } type Mutation { commentOnEvent(eventId: ID!, location: String, content: String): Comment } type Subscription { subscribeToEventComments(eventId: String!, location: String, content: String): Comment @aws_subscribe(mutations: ["commentOnEvent"]) }

新しいオプションフィールド Comment.location に注目してください。

特定のイベントについて投稿されたすべてのコメントが通知されるようにする場合は、以下のサブスクリプションを作成します。

subscribeToEventComments(eventId: "1") { eventId commentId location content }

代わりにフィールド引数 location: null を上記のサブスクリプションに追加するとします。

subscribeToEventComments(eventId: "1" location: null) { eventId commentId location content }

これで、質問は変わりました。このサブスクリプションは、特定のイベントについて場所を指定していないすべてのコメントが通知されるように、クライアントを登録します。