失敗から学ぶAppSyncのSubscriptionとかApolloとかPostmanとか

こんにちは。てぃろです。

今回はAppSyncでSubscriptionのクライアントを作ろうとして失敗した話です。個人的に学びが多かったので記事にまとめます。

そもそもやりたかったことは、AppSyncのSubscriptionへVue+Apolloでクライアントを作ってアクセスしたかっただけです。そのためにいろんな試行錯誤をしましたが、結局諦めました…。

今回は力尽きたのですが、また気が向いたらトライしようと思います。絶対設定とかでできると思うんだけどなー!

失敗の原因は、AppSyncのSubscriptionとApolloのuseSubscriptionはリクエストの形が合わないこと

最終的に失敗に終わった原因は、AppSyncのSubscriptionで受け入れるリクエストの形式とApolloのuseSubscriptionで送られるリクエストの形式が合わないことでした。

まず、AppSyncのSubscriptionで受け入れるリクエストは以下のような形式です。

{
    "id": subscriptionId,
    "type": "start",
    "payload": {
        "data": {
            "query": query,
            "variables": {topicId: topicId},
        },
        "extensions": {
            authorization: {
                host: endpoint,
                "x-api-key": apikey,
            }
        },
    }
}

一方、Apolloで使えるuseSubscriptionでは、こんなリクエストの形式でした。

{
    "id": subscriptionId,
    "type": "start",
    "payload": {
        "variables": {},
        "extensions": {},
        "operationName": subscriptionName,
        "query": quey
    }
}

おおよそ受け入れるパラメータは似たものが多いですが、payloadの階層構造があっていなかったのです。

加えて、AppSyncではエンドポイントのURLにheaderやpayloadをbase64エンコードしてつける必要があり、その点でも少し工夫が必要になるということがわかりました。

もしここからApolloを使ってAppSyncのSubscriptionの接続をしようと思ったら、以下の工夫をする必要がありそうです。

  • payloadの形式をAppSyncの形式にどうにかして合わせる
  • WebSocketクライアントの設定時にheaderとpayloadをbase64エンコードして付与する
    • つまり複数のSubscriptionが必要な場合には、その数だけWebSocketクライアントを用意する必要がある
    • 参考:https://apollo.vuejs.org/guide/multiple-clients.html

また、こちらの記事にあるようにApolloLinkというのを使えば問題なくなるという話もありますが、これのコピペでは使えないです。そのまま使うとReactが必要になるようなエラーが出ていてVueで使うには少し工夫が必要そうでした。

ここからは力尽きるまでにやったことを書いておきます。

失敗の経緯

ドキュメントをよく読め、という話になるのですが、ここに至るまでの経緯と合わせて順に書いていきます。自分への戒めもかねて…。

経緯1:PostmanでWebSocket使えないのか! -> 使えました

これまで以下の通りAppSyncをServerless Frameworkを使って書いてきました。

ここで動作確認に使っていたクライアントは、Postmanです。QueryとMutationは、httpのPOSTで動作するので容易に使うことができました。

しかし、SubscriptionはWebSocketです。Postmanは一見WebSocketができないように見えるので使えない!と思ってたんですが…実は使えました

まだBetaと表示はありますが使えます。公式のブログはこちら。

どこで作れるかだけお伝えしておくと、画面左上の「New」をクリックすると以下のよう画面が開きますので、ここからWebSocketリクエストが作れます。

おバカな私はここでいろいろ試したのですが、WebSocket繋がらないじゃん!クライアント作ってみよ!となったのでした。ドキュメント読んでみればよかった…。

payloadとheaderの作り方はドキュメントに書いてあります。正直わかりにくいとは思うのですが、よく読めばどのようにPostmanでリクエストすればよいかわかりそうなものです。

経緯2:Apolloのドキュメントが新旧入り混じってわかりにくかった

クライアントを作ろうと思い立ったわけですが、Vueと合わせて使ってよさそうなライブラリを探して見つけたのがApolloだったのです。

Apolloを使うのが初めてなのでドキュメントをしっかり読んでいるつもりでしたが、何かうまくいかない…。原因はv3とv4のドキュメントがGoogle検索で見つけていった記事に混ざっていたことでした。

「Vue Apollo」で出てくるドキュメントはこちら。これはv3です。

しかし使うべき最新のv4のドキュメントはこちら。見た目にもほとんど同じで全然わからなかった…。これは初見殺し…(泣

ということで、まずApolloを使い始めるまでに非常に時間がかかりました。その違いを学び、v4を使うようにしました。

経緯3:ApolloでSubscriptionをやってみるがよくわからないエラー…

Apolloがクエリを投げるための仕組みは新旧二つあります。Option APIとComposition APIの二種類です。Composition APIのほうが新しくいろいろ使い方が便利になっています。当然今回も実装はこちらで進めました。

まだ試しに実装している段階でしたが、以下のようなエラーメッセージが出てきます。

message: "Both, the \"header\", and the \"payload\" query string parameters are missing"

header?payload?となるわけです。

ここでApolloのドキュメントを見てみます。
Subscriptionのために使っていたメソッドはuseSubscriptionなのでそのドキュメントを見てみます。

引用:https://v4.apollo.vuejs.org/api/use-subscription.html#parameters

payloadもheaderもない…!

あれ、じゃあAppSyncのほうを見てみると…

headerとpayloadを要求している…。

でもこれ具体的にはどう実装するのか?既に実装をされている方がいたので、そのソースを見せていただきました。

AWS AppSyncのGraphQL Subscriptionsのクライアントを作って裏側の仕組みを学ぶ

最後にある makeStartSubscriptionMessageData 以降がポイントです。payloadの作り方やheaderとpayloadの送り方などがよくわかります。

そうしてApolloで実装するにはリクエストの形が合わないことを悟りました。

こうしてApp SyncのSubscriptionをApolloでやることを諦めました。

まとめ

失敗すると学ぶことが多いのはほんとうですね。今回私はこれだけのことが学べました。

  • PostmanはWebSocketを使える!
  • VueでGraphQLを扱うにはApolloを使えばよい
  • ApolloはV4を使うべし
  • V4の中でも、クエリをするならComposition APIを使おう
  • AppSyncのクライアントを実装するなら、AmplifyなどAWSが提供しているものを使うのが無難
  • WebSocketを使ったAppSyncのハンドシェイクの方式を(ざっくり)理解した
  • ドキュメントをもうちょっとしっかり読もう

ちなみに、ApolloでQueryは非常に簡単に実装できたので、今回私が失敗して諦めたのはSubscription部分だけです。QueryやMutationの実装を進める分には非常に簡単にできるので、今後も使いたいライブラリです!