公開日:2020-11-03
Amplify DataStore を使っていますか?
Amplify DataStore を使うと、クラウドと連携するアプリケーションを容易に開発することができます。
例えば POS のようにオフラインでも高速に動作する必要があるが、定期的にサーバーサイド(物理サーバーを使用しないので何と表現するのが良いでしょうか・・クラウド側というかバックエンドというかマネージドデータベースというか)へデータを送り、複数の端末で共有したいアプリケーションには Amplify DataStore がまさにオススメです。POSのデータ同期の仕組みをイチから開発するような時代ではないのです。
また、入退室管理のような仕組みにも Amplify DataStore はオススメです。カードキーをかざした人を入室させて良いかはローカルで高速に判定しつつ、履歴はクラウドへ即座に・継続的に同期する、まさにそんな仕組みを作る際には Amplify DataStore の有り難みが身に染みるはずです。
他にも Amplify DataStore が有効なユースケースは多数考えられます。localStorage や Redux を使っているなら、それを Amplify DataStore に置き換えることを検討してみてください。そうです。Amplify DataStore はあらゆる state に適用できる可能性があります。
そんな Amplify DataStore に “Selective Sync” という新機能が追加されました。
Selective Sync は何を解決するのでしょうか? Amplify DataStore についておさらいしながら考えていこうと思います。
まず基本的な Webアプリを作成します。
このブログでも以前に Amplify DataStore の基本について説明した記事を書いたのですが、なぜか Ionic を使ってしまいました。(実際には中身はただの React なのですが)
Amplify DataStore (や AWS AppSync, Amplify)のワークショップ(サンプル)が https://amplify.aws/community/resources にまとめられています。
Angular でも React でも Vue でも好きなものを選んでください。私は今回 Vue を使用することにしました。
そして Amplify DataStore が動作するところまで ワークショップを進めたファイルを https://github.com/r3-yamauchi/amplify-datastore-chatty-vue/tree/DataStore に置いています。amplify init や amplify add api は各々の環境で行う必要がありますが、参考にはなると思います。
この状態で Webアプリを実行すると、DataStore の読み書き、AWS側(DynamoDB)との同期が行えるようになっています。(この記事の状態)
どのようなユーザーでログインしても、全ての人が書き込んだ全てのデータが流れてくるようになっています。
自分が書き込んだ情報を自分にしか見られない(他人が書き込んだ情報は参照できない)ようにするにはどうすれば良いでしょうか。
GraphQL Transformer内で @auth ディレクティブを使う方法があります。
以下のように schema.graphql で model に @auth ディレクティブを付けると オーナー認可することができます。
このうえで amplify codegen models して amplify push すると、同じユーザーでログインした書き込みのみ参照でき、subscribe されるようになります。
この状態のコードを https://github.com/r3-yamauchi/amplify-datastore-chatty-vue/tree/auth に置きましたので参考にしてください。
(以前の状態との差分は https://github.com/r3-yamauchi/amplify-datastore-chatty-vue/compare/DataStore…r3-yamauchi:auth )
以上は、従来でも実現できました。
“Selective Sync” (以降では syncExpression と呼ぶことにします)を使用すると DynamoDB を条件検索して、一部のデータのみを Amplify DataStore と同期することができるようになりました。
(なお、https://docs.amplify.aws/lib/datastore/conflict/q/platform/js#example で示されている通り、DataStore.configure で maxRecordsToSync や fullSyncInterval というパラメータを渡して DataStore と同期するレコード数に上限をかけたり、同期する間隔を指定することができたようです・・)
syncExpression を試した例が https://github.com/r3-yamauchi/amplify-datastore-chatty-vue/commit/93e4a1386fa99f2e50491c080b946f79c07bb597 です。
モデルに rate という Int 型の項目を追加し、 syncExpression で rate に 5以上 7以下の値を指定した場合のみ クラウド(DynamoDB)と同期するように指示しています。
クラウド(DynamoDB)と同期しないデータは他の端末へは伝搬されません。
この機能はどのようなユースケースで使用できるのでしょうか?
Ricardo が Twitter に書いていたように @auth ディレクティブではカバーしきれない「マルチテナント」(データの分離)で使用することが思い浮かびます。
また、古いデータは同期せず、直近のデータのみを同期してレスポンスを上げるためにも使用できます。
従来は Amplify DataStore と同期させている DynamoDB テーブルには あまり長期間データを置くことはせず、DynamoDB Streams を使用して他へ書き出し、TTLを設定して一定期間後に削除するのがお決まりのパターンでした。
相変わらず TTLを設定するケースが多いとは思いますが、そのうえで ページ送りや無限スクロールを実装する際に syncExpression を使用できそうです。
Reevaluate expressions at runtime の項で説明されている通り、syncExpression の内容を切り替えることができるからです。
また @key ディレクティブを指定すれば DynamoDB に GSI を付け、scan を避けることもできるようです。
Amplify DataStore のパフォーマンスに悩まされていた方はぜひ “Selective Sync” を試してみる価値がありそうです。
ページ送りや無限スクロールを GraphQLクエリ(で AWS AppSyncにアクセスする)で実装するのは、定形パターンではありますが手間がかかります。
Amplify DataStore の方が圧倒的にラクなのではないでしょうか?
Amplify DataStore は決して GraphQL(AWS AppSync)を置き換えるものではないので、まずは Amplify DataStore を使って実装することを考え、足りない部分を DynamoDB Stream や AppSync で補うように考えるのが良いように思います。