date: 2021-03-02

GraphQLのSubscriptionについて

Subscriptionとは


SubscriptionはGraphQLの仕組みの一つで、GraphQLサーバーにデータ変化などの特定のイベントが生じるたびにクライアント側に通知(データ)を送るPubSub通信の一つです.

主なユースケースとしてはチャットアプリやお知らせ通知などです。

ここではNode.jsのExressとapollo-serverを利用して実践してみます。ちなみにNode.js + GraphQL を触ったことない方はこちらをチェックしておいてください。

Subscriptionの実装


今回はこちらのGraphQL + Node.jsのチュートリアルのを使用して解説していきます。

 
  // src/index.js
  const { PubSub } = require('apollo-server-express')
  //.....
  const pubsub = new PubSub()
 

contextからpubsubにアクセスできるようにしてあります。

 
 // src/index.js
  const server = new ApolloServer({
    typeDefs,
    resolvers,
    context: ({ req }) => {
        return {
            ...req,
            prisma,
            pubsub
        }
    }
 })
 

これでresolver内でもcontext.pubsubからsubscriptionsを実装するための方法にアクセスができます。

続いてQueryやMutationのようにスキーマ内にSubscription型を定義します。

 
 // src/typeDefs.js
 //...
 type Subscription { 
    newTodo: Todo 
 }
 

次にnewTodoのためのresolverを実装していきます。ここでのresolver内はQueryやMutationのそれとは大きく異なります。

src/subscription/newTodo.jsのファイルを作成して以下のように実装していきます。

 
function newTodoSubscribe(_, __, context) {
    return context.pubsub.asyncIterator("newTodo")
}
const newTodo = {
    subscribe: newTodoSubscribe,
    resolve: payload => {
      return payload
    },
}
module.exports = {
    newTodo,
}
 

asyncIteratorはGraphQLサーバーがクライアント側にイベントの発生を通知します。src/index.jsでcontextからアクセスできるようにしているのでcontext.pubsub.asyncIterator("newTodo")で newTodoSubscribeのresolver関数はsubscribeフィールドの値として与えられます。resolveはasyncIteratorによってでたデータをかえします。

最後にaddTodoのMutation内にcontext.pubsub.publish("newTodo", newTodo)を追加します。"newTodo"というnewTodoSubscribe関数に追加したメッセージと同じものをpublishにわたしてあげます。第二引数にはnewTodoをわたします。

 
addTodo: async(_, { content }, context ) => {
    if(!context.session.userId){
        return null;
    }
    const newTodo = await context.prisma.todo.create({
        data: {
            content,
            user: { connect: { id: context.session.userId } },
        }
    })
    // 追加
    context.pubsub.publish("newTodo", newTodo)
    return newTodo
},
 

ここまでできたらサーバーをはしらせてPlaygroundで試しましょう。

Subscriptionを利用するには、クエリを書いた後にYouTubeの再生ボタンのような矢印をクリックします。 上のようにListening...が表示されたら、Subscriptionの起動成功です。

 
 mutation {
  addTodo(content: "Go to park"){
    id
    content
  }
}
 

上のようにmutation addTodoをはしらせたらもう一度確認すると

結果がかえってきています。

Mutationによるデータの更新をSubscriptionを通して確認することが出来ました。またupdateTodoなどのMutationでも試してみてください。

こちらが実際のコードなので詰まった人は確認してみてください。:Githubコード