NestJS + GraphQLの@Subscriptionが実行されない、値を取得できない時に見る設定部分

Node.jsでGraphQLをやりたい~という時にTypeGraphQLやNexus、Pothosなど選択肢がありますが、TypeGraphQLとNexusはコミュニティのメンテナンス的な問題で敬遠し、Pothosも個人の方が中心でメンテしているので、なかなか採用しづらい…という状況が現在起きていると思います(2024年時点)

で、TypeGraphQLの開発者がNestJSの方と同じなので、
NestJSのGraphQLはTypeGraphQLと書き味ほぼ同じですし、

メンテナンス的にもNestJSは今後も生き残っていきそうだからNestJSで良いよね~となると思います(私のケースではそういう事情でNestJSを使っています~)

基本のGraphQLはNestJSでも全然使いやすいのですが、
1点だけ、Subscriptionの設定が非常に分かりづらくてハマります

というか、ハマったのでこの記事をご覧になっているかなと思います

結論から書くと、

    @Subscription(() => GeneratedAiText)
    generateAiText() {
        return pubSub.asyncIterableIterator('generateAiText');
    }

上記のような感じで書いているSubscriptionが、
構文的には正しいのにフロントエンドで値を取得できない、generateAiText()関数も実行されない~という時の理由は、websocketの設定です

app.module.tsに書いているでしょうwebsocketの設定のうち、
subscriptionsという項目を’graphql-ws’でもなく、’graphql-transport-ws’でもなく、
下記のように’subscriptions-transport-ws’にしてください

      subscriptions: {
        'subscriptions-transport-ws': true,
      },

そして、フロントエンドのApollo Clientのwebsocketの設定を、

import { WebSocketLink } from '@apollo/client/link/ws';
import { SubscriptionClient } from 'subscriptions-transport-ws';

const wsLink = new WebSocketLink(
    new SubscriptionClient('ws://localhost:4000/graphql', {
        reconnect: true,
        connectionParams: {
            // 必要に応じて認証情報などを追加
        },
    })
);

という感じで、subscriptions-transport-wsで統一してください
参考記事: https://qiita.com/mu-suke08/items/6dc353dd641e352f350e

NestJSやApollo Clientのwebsocketの設定で調べたら、graphql-wsを使おうという話がよく出てきますが動きません(issueやDiscordでも議論されているようです)

なので、例えば下記の設定では@Subscriptionは実行されず、値を取得することもできません

サーバーサイドの設定を、

      subscriptions: {
        'graphql-ws': true,
      },

や、

      subscriptions: {
        'graphql-ws': {
          path: '/graphql',
        }
      },

↑としたら、そもそもこれはwebsocketの通信自体に失敗します…

次に、

      subscriptions: {
        'graphql-transport-ws': true,
      },
      subscriptions: {
        'graphql-transport-ws': {
          path: '/graphql',
        }
      },

↑とすると、接続には成功しますが、
エラーは出ないものの、@Subscriptionのメソッドは実行されず、フロントエンドにも値は返されません

上記のようなサーバーサイドの設定と、下記のようなフロントエンドの設定だと失敗します

const wsLink = new WebSocketLink({
    uri: 'ws://localhost:4000/graphql',
    options: {
        reconnect: true,
    },
});

困ったものですね…

ライブラリのメンテナンス的にはgraphql-wsが推奨されると思いますが、NestJSで動かないので、仕方ないですがいったんsubscriptions-transport-wsを使うしかないかなと思います

ChatGPTなど生成AIの台頭でリアルタイム、ストリーム通信をwebsocketでやりたい~というニーズが増えてきていると思うので、備忘録的に残しておきます~