概要
リアルタイムデータの反映のためにsubscriptionを利用しています。@modelでsubscriptionを自動生成していましたが、自動生成ではフィルタリングができず、関係のないデータが一時的に表示されてしまう問題がありました。そこで、subscriptionを手動で作成し、引数でフィルタリングするようにしました。
実装
スキーマ
これまでは@modelでsubscriptionを自動生成していました。
type Task
@model(subscriptions: { level: public })
{
id: ID!
name: String!
detail: String
}
↓生成
export const onCreateTask = /* GraphQL */ `
subscription OnCreateTask {
onCreateTask {
id
name
detail
}
}
`;
export const onUpdateTask = /* GraphQL */ `
subscription OnUpdateTask {
onUpdateTask {
id
sequence
name
detail
}
}
`;
export const onDeleteTask = /* GraphQL */ `
subscription OnDeleteTask {
onDeleteTask {
id
name
detail
}
}
`;
しかし、自動生成ではフィルタリングできません。
そのため、@modelでsubscriptionを自動生成しないように設定します。
type Task
@model(subscriptions: null)
{
id: ID!
name: String!
detail: String
}
次に独自のsubscriptionをschema.graphql
に追加します。
Subscription名(引数): 型 @aws_subscribe(mutations: [Mutation名])
のように書きます。
type Subscription {
onCreateTaskByName(name: String): Task
@aws_subscribe(mutations: ["createTask"])
// Mutationのtypeはcreate・update・deleteの3種類。必要に応じて設定。
onUpdateTaskByName(name: String): Task
@aws_subscribe(mutations: ["updateTask"])
onDeleteTaskByName(name: String): Task
@aws_subscribe(mutations: ["deleteTask"])
}
↓生成
export const onCreateTaskByName = /* GraphQL */ `
subscription OnCreateTaskByName($name: String) {
onCreateTaskByName(name: $name) {
id
name
detail
}
}
`;
export const onUpdateTaskByName = /* GraphQL */ `
subscription OnUpdateTaskByName($name: String) {
onUpdateTaskByName(name: $name) {
id
name
detail
}
}
;`
export const onDeleteTaskByName = /* GraphQL */ `
subscription OnDeleteTaskByName($name: String) {
onDeleteTaskByName(name: $name) {
id
name
detail
}
}
;'
これでsubscriptionに引数が渡せるようになり、フィルタリングをすることができるようになりました。
また、引数を複数設定することも可能です。引数を複数設定した場合はその引数に完全一致した場合のみsubscribeします。
type Subscription {
onCreateTaskByName(name: String, detail: String): Task
@aws_subscribe(mutations: ["createTask"])
}
呼び出し
import Amplify, { API } from "aws-amplify";
import { subscriptions } from "src/graphql/subscriptions";
function subscribe() {
const subscription = API.graphql({
query: subscriptions.onCreateTaskByName,
variables: {
name: "Test",
},
}).subscribe({
next: ({ provider, value }) => {
console.log("Subscribe:", { provider, value });
subscription.unsubscribe();
},
error: (error) => console.warn(error),
});
};
これで「Test」というnameのタスクを作成した時だけsubscribeできるようになりました。
graphqlOperationを利用する場合は下記のようにします。
import Amplify, { API, graphqlOperation } from "aws-amplify";
import { subscriptions } from "src/graphql/subscriptions";
function subscribe() {
const subscription = API.graphql(
// TypeScriptを利用している場合は型定義も可能
graphqlOperation(subscriptions.onCreateTaskByName as 型, {
name: "Test",
})
).subscribe({
next: ({ provider, value }) => {
console.log("Subscribe:", { provider, value });
subscription.unsubscribe();
},
error: (error) => console.warn(error),
});
};
注意点
- mockで動作しない
これでハマりました...
issueにmockで動作しないことが挙がっていました。closeされていますが、改修はされていないようです。そのため、毎回codgenを実行し、pushする必要があります。また、codegenでsubscriptionが自動生成されないことがありました。その場合は一度mockを起動すると生成可能です。
*2021/03 現在
issue:https://github.com/aws-amplify/amplify-cli/issues/6026
参考
(公式)
- Examples
- リアルタイムデータ
-
Subscribe to data
(ブログ) - AWS AppSync + Amplifyで、Subscriptionに引数を追加し、一部のみ通知を受け取ってみた
- Miyata Koki - [O:inc.](https://o-inc.jp/)でAmplify×React×React Nativeを使用して開発しています。大学のゼミでは統計学をPythonで行っています。 インターンやゼミで学んだ情報を発信していくので、フォロバするのでぜひこちらのアカウントのフォローお願いします!