AWS AppSyncでは、Subscriptionを使うことでMutationに対する通知を受け取ることができます。
リアルタイムデータ - AWS AppSync
また、AWS AppSyncにAWS Amplifyを組み合わせた場合でも、Amplify FrameworkのSubscriptionが使えます。
Subscription | AWS Amplify | API
ドキュメントを読んでいたところ、Subscriptionに引数を追加することで、一部のMutationに対してのみ通知を受け取ることもできそうでした。
そこで、AWS AppSync + Amplifyで試してみたため、その時のメモを残します。
目次
環境
- AWS AppSync
- AWS Amplify JavaScript 1.1.32
Schemaと確認内容
今回用意したAmplifyの schema.graphql
はこちらです。
type Blog @model(queries: {get: "getBlog"}, mutations: {create: "createBlog"}, subscriptions: { onCreate: [ "none", "titleOnly(title: String!)", "all(title: String!, content: String)", ]}) @key(fields: ["title"]) { title: String! content: String }
これをデプロイすると、AppSync Console上のSchemaは以下のような感じになります。
type Blog { title: String! content: String } input CreateBlogInput { title: String! content: String } type Mutation { createBlog(input: CreateBlogInput!): Blog } type Query { getBlog(title: String!): Blog } type Subscription { none: Blog @aws_subscribe(mutations: ["createBlog"]) titleOnly(title: String!): Blog @aws_subscribe(mutations: ["createBlog"]) all(title: String!, content: String): Blog @aws_subscribe(mutations: ["createBlog"]) }
今回は、このSchemaに対し、3つのSubscription
- none (引数なし)
- titleOnly (キーtitleのみの引数)
- all (キーtitle、およびそれ以外の項目(content)も引数に含む)
を実行した後にMutation createBlog
を実行することで、各Subscriptionがどのように動作するかを確認します。
動作確認用の環境として、以下の index.html と src/app.js を用意しました。
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Amplify Framework</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div class="app"> <div>フィルターなし <button id="none">Non Filter</button> </div> <div>タイトルだけ (title=foo) <button id="title_only">Title Only</button> </div> <div>すべて (title=foo, content=bar) <button id="all">All Filter</button> </div> <div>データ作成 <label for="title">タイトル</label> <input type="text" id="title" placeholder="my title" /> <label for="content">内容</label> <input type="text" id="content" placeholder="my content" /> </div> <div> <button id="create">Create</button> </div> </div> <script src="main.bundle.js"></script> </body> </html>
app.js
subscriptionを実行する時の引数は、それぞれ以下を指定しました。
subscriptionsのメソッド | 引数 |
---|---|
none | なし |
titleOnly | title = 'foo' |
all | title = 'foo' , content = 'bar' |
また、一度通知を受け取ったら再度受け取らないよう、 unsubscribe()
メソッドを使って通知を中止しています。
https://aws-amplify.github.io/docs/js/api#subscriptions
import Amplify, { API } from 'aws-amplify'; import awsconfig from './aws-exports'; import * as mutations from "./graphql/mutations"; import * as subscriptions from "./graphql/subscriptions"; // データ作成 const creteButton = document.getElementById('create'); creteButton.addEventListener('click', () => { Amplify.configure(awsconfig); API.graphql( { query: mutations.createBlog, authMode: 'API_KEY', variables: { input: { title: document.getElementById('title').value, content: document.getElementById('content').value, } } } ).then((data) => { console.log('created: target data.'); console.log(data); }) .catch((e) => { console.log('mutation error'); console.log(e) }); }); // -------------------------- // Subscriptions // -------------------------- // non filter const nonFilterButton = document.getElementById('none'); nonFilterButton.addEventListener('click', () => { Amplify.configure(awsconfig); console.log('subscribe(none): start...'); const client = API.graphql( { query: subscriptions.none, authMode: 'API_KEY', } ).subscribe({ next: (data) => { console.log('subscribed: none'); console.log(data); // 一回通知を受け取ったら、それ以降は受け取らないようにする client.unsubscribe(); console.log('finish: none'); }, error: (err) => { console.log(err); client.unsubscribe(); console.log('sub error (none)'); }, close: () => console.log('sub done') }) }); // title filter const titleFilterButton = document.getElementById('title_only'); titleFilterButton.addEventListener('click', () => { Amplify.configure(awsconfig); console.log('subscribe(title): start...'); const client = API.graphql( { query: subscriptions.titleOnly, authMode: 'API_KEY', variables: { title: "foo" } } ).subscribe({ next: (data) => { console.log('subscribed: title'); console.log(data); client.unsubscribe(); console.log('finish: title'); }, error: (err) => { console.log(err); client.unsubscribe(); console.log('sub error (title)'); }, close: () => console.log('sub done') }) }); const allButton = document.getElementById('all'); allButton.addEventListener('click', () => { Amplify.configure(awsconfig); console.log('subscribe(all): start...'); const client = API.graphql( { query: subscriptions.all, authMode: 'API_KEY', variables: { title: "foo", content: "bar" } } ).subscribe({ next: (data) => { console.log('subscribed: all'); console.log(data); client.unsubscribe(); console.log('finish: all'); }, error: (err) => { console.log(err); client.unsubscribe(); console.log('sub error (all)'); }, close: () => console.log('sub done') }) });
動作確認
どのSubscriptionの引数にも一致しないtitleのMutationを実行
title = 'ham' , content = 'spam' のMutationを実行した時は
- 引数なしの
none()
のSubscriptionで通知を受け取りました。
一部の引数ありのSubscriptionに一致する、titleが "foo" のMutationを実行
title = 'foo' , content = 'spam' のMutationを実行した時は、
- 引数なしの
none()
- 引数 title = 'foo' を設定した
titleOnly()
の2つのSubscriptionで通知を受け取りました。
引数ありのSubscriptionすべてに一致する、titleが "foo" & contentが "bar" のMutationを実行
title = 'foo' , content = 'bar' のMutationを実行した時は、すべてのSubscriptionで通知を受け取りました。
まとめ
以上より、Mutationでの更新内容とSubscriptionの引数値がすべて一致した場合に、通知を受け取れるようでした。
例えば
const client = API.graphql( { query: subscriptions.all, authMode: 'API_KEY', variables: { title: "foo", content: "bar" } } )
は、title == "foo" && content == "bar" のMutationのみ通知を受け取るようです。
ソースコード
Githubに上げました。 filter_subscription
ディレクトリ以下が今回のファイルです。
https://github.com/thinkAmi-sandbox/AWS_AppSync_Amplify-sample