22
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VueAdvent Calendar 2019

Day 23

vue-apolloでのsubscriptionの設定方法(リアルタイム同期のChatアプリのサンプル付き)

Last updated at Posted at 2019-12-22

この記事はVue.js Advent Calendar 23日目の記事です。

リアルタイム更新というとFirebase Firestoreが思い浮かびますが、
実はGraphQLのsubscriptionを使っても手軽に出来ます!
vue-apolloでのsubscriptionの設定についての日本語記事があまりなかったので今回紹介します。

サンプルアプリ

「説明いらんから、はよコード」という方は、こちらから。
https://github.com/kawamataryo/hasura-vue-chat-app

subscriptionsの練習用に作ったリアルタイム同期のチャットアプリです。
HasuraでGraphQLサーバーを立てて、vue-apolloでsubscriptionを行っています。
READMEの通り起動すれば数分でhasura, vue-apolloのsubscriptionを体験できます。
(練習用に作ったので優しい目でお願いします。。)

Dec-21-2019 16-44-3.gif

Subscriptionとは?

GraphQLでのWebSocketを使ったリアルタイムデータ通信の手段です。
subscriptionsを使うと、更新された内容をページリロードなしにリアルタイムでサーバーから、Webページに直接通知することが出来ます。

vue-apolloの設定

では本題のvue-apolloのsubscriptionの設定です。
ポイントは、クエリの種別でhttp通信にするか、websocket通信にするか設定しているところです。
new HttpLinkでhttp、new WebSocketLinkでwebsocketのエンドポイントを設定し、
split関数で呼ばれるクエリによって向き先を変更しています。

import Vue from "vue";
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";
import { split } from "apollo-link";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";
import VueApollo from "vue-apollo";

// 通常のquery, mutationsで使われるhttp通信のエンドポイントを指定
const httpLink = new HttpLink({
  uri: "http://localhost:8000/v1/graphql"
  // トークンによる認証を追加する場合は以下のように設定
  // headers: {
  //   authorization: `Bearer xxxxx`
  // }
});

// subscriptionで使われるwebsocket通信のエンドポイントを指定
const wsLink = new WebSocketLink({
  uri: "ws://localhost:8000/v1/graphql",
  options: {
    reconnect: true
 // トークンによる認証を追加する場合は以下のように設定
 // headers: {
 //   authorization: `Bearer xxxxx`
 // }
  }
});

// GraphQLのエンドポイントの向き先をクエリの種別で分離するための設定
// 参考 https://www.apollographql.com/docs/link/composition/#directional-composition
const link = split(
  ({ query }) => {
    // クエリから種別を取得してsubscriptionの場合は、wsLink(websocket)を利用する。
    const definition = getMainDefinition(query);
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    );
  },
  wsLink,
  httpLink
);

// Apollo Clientの作成
const apolloClient = new ApolloClient({
  link,
  cache: new InMemoryCache(),
  connectToDevTools: true
});

Vue.use(VueApollo);

// vue-apolloへの接続
export const apolloProvider = new VueApollo({
  defaultClient: apolloClient
});

subscribeの実行

サンプルアプリのコードをもとに説明します。
通常のvue-apolloのquery内にsubscriptionsToMoreを追加することでそのqueryに紐づくデータをsubscriptionsの結果でリアルタイム更新することが出来ます。
documentにsubscriptionのクエリを設定し、対象のデータに変更がある場合、updateQueryで設定した関数が呼ばれ、queryに紐づくデータ(この場合はmessages)が更新されます。

export default {
  data() {
    return {
      messages: []
    }
  },
  apollo: {
    messages: {
      query: gql`
        query {
          messages {
            content
            userId: user_id
            iconColor: icon_color
            id
          }
        }
      `,
      subscribeToMore: {
        document: gql`
          subscription {
            messages {
              id
              userId: user_id
              iconColor: icon_color
              content
            }
          }
        `,
        updateQuery: (previousResult, { subscriptionData }) => {
          return subscriptionData.data;
        }
      }
    }
  .
  .
  .
}

終わりに

以上、vue-apolloでのsubscriptionsの設定方法でした。
リアルタイム更新をしようと思うとぱっと思いつくのはFirestoreですが、GraphQLのSubscriptionも手軽でおすすめです。(Hasuraを使えばなおさら)

vue-apolloは、上手くApolloをVue.js仕様にラップしていて僅かなコードでGraphQL触れるのでとても良いですね。

参考

https://vue-apollo.netlify.com/guide/apollo/subscriptions.html#setup
https://www.howtographql.com/vue-apollo/8-subscriptions/

22
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?