Next.js + サーバーサイドTypeScript + 関数フレーバーでクリーンなアプリを作ったので実装意図とか書く Advent Calendar 2022
の21日目。株式会社mofmofに生息しているshwldです。
前日はMailgunでメーラーを実装するについて書きました
Next.jsでGraphQL Subscription環境を構築する
クライアントサイド (next-urql)
withUrqlClient((_ssrExchange, _ctx) => ({
url: `${API_HOST}/api/graphql`,
exchanges: [
dedupExchange,
cache,
fetchExchange,
yogaExchange(),
],
})
source: /apps/web/src/graphql/withGraphQLClient.tsx
サーバーサイド
Pub/Subの実装
pg-pubsubを使っています。
今回PostgreSQLのPub/Subを使おうと思ったのは、インフラコスト削減が理由でした。
また、当初GraphQL Yogaを使っていなかったのもありました。
調べていると無料Redisも多少あるのと、途中でYogaに乗り換えたので、普通に実装するならRedisとYogaを使って実装するのが良い気がしています。
幸いPub/Subクライアントの実装をインフラ層で行っているので、乗り換えるのは簡単な構造になっています。
import PGPubsub from 'pg-pubsub';
import type { Pubsub } from 'domain-interfaces';
import asyncify from 'callback-to-async-iterator';
const storyChannelName = (projectId: string) => `project-${projectId}-stories`;
export const createPubsubClient = (): Pubsub => {
const pubsubInstance = new PGPubsub(process.env.DATABASE_URL);
return {
story: {
subscribe({ projectId }) {
return asyncify(async handler => {
pubsubInstance.addChannel(storyChannelName(projectId), handler);
});
},
publish(item) {
pubsubInstance.publish(storyChannelName(item.object.projectId), item);
},
},
};
};
source: /infrastructures/db-pubsub/src/index.ts
Subscribe
const subscribed = context.pubsub.story.subscribe({
projectId: args.projectId,
});
for await (const it of subscribed) {
if (it.triggeredBy.id === context.currentUser.id) continue;
yield {
subscribeStoryUpdate: it.object,
};
}
Publish
context.pubsub.story.publish({
object: story,
triggeredBy: user,
})
次回予告
明日はバックグラウンドワーカーについて書きます。