AWS AppSync + Amplifyで、Subscriptionに引数を追加し、一部のみ通知を受け取ってみた

AWS AppSyncでは、Subscriptionを使うことでMutationに対する通知を受け取ることができます。
リアルタイムデータ - AWS AppSync

また、AWS AppSyncにAWS Amplifyを組み合わせた場合でも、Amplify FrameworkのSubscriptionが使えます。
Subscription | AWS Amplify | API

 
ドキュメントを読んでいたところ、Subscriptionに引数を追加することで、一部のMutationに対してのみ通知を受け取ることもできそうでした。

そこで、AWS AppSync + Amplifyで試してみたため、その時のメモを残します。

 
目次

 

環境

 

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で通知を受け取りました。

f:id:thinkAmi:20190721204206p:plain:w450

 

一部の引数ありのSubscriptionに一致する、titleが "foo" のMutationを実行

title = 'foo' , content = 'spam' のMutationを実行した時は、

  • 引数なしの none()
  • 引数 title = 'foo' を設定した titleOnly()

の2つのSubscriptionで通知を受け取りました。

f:id:thinkAmi:20190721204836p:plain:w450

 

引数ありのSubscriptionすべてに一致する、titleが "foo" & contentが "bar" のMutationを実行

title = 'foo' , content = 'bar' のMutationを実行した時は、すべてのSubscriptionで通知を受け取りました。

f:id:thinkAmi:20190721205009p:plain:w450

 

まとめ

以上より、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