Prisma 2에서 Subscription 구현하기
요약
Prisma 2에서는 Subscription을 지원하지 않는다. (Issue 링크)
이슈 게시글을 보면 Subscription을 지원하기 위해 작업하고 있다고 적혀 있지만, Prisma 팀에서 공개한 로드맵에도 Subscription은 존재하지 않는다.
그러면 어떻게 하지? 직접 만들어야지 뭐 😮💨
작업 환경
필자가 작업하는 환경은 아래와 같다.
- 언어는 TypeScript 사용
- 제목과 같이 Prisma 2 ORM + nexus
- 웹 서버로 fastify + mercurius 사용
- AWS Lambda 환경에 구축되어 있음
아이디어를 얻어보자 🧐
다행히, Prisma 2에서 Subscription을 지원하지 않아 곤란한 사람은 우리만 있는게 아니다.
위에서 링크해둔 이슈 게시글만 봐도 많은 사람들이 아이디어를 공유하고 있다.
Mercurius에서는 Subscriptions을 지원하고 있어, 해당 방법을 통해 구현해보고자 한다.
Mercurius에서 제공하는 Subscriptions 관련 Document는 아래 링크에서 확인 가능하다.
https://mercurius.dev/#/docs/subscriptions
구현
우선 WebSocket 사용을 위해 fastify-websocket을 설치한다.
yarn add fastify-websocket
그리고, 기존 mercurius 설정이 있는 곳에 아래 코드를 추가한다.
코드의 내용은 fastify-websocket을 import하고, fastify 앱에 등록하는 코드이다.
// ..import
import fastifyWebsocket from 'fastify-websocket';
// ..codes
app.register(fastifyWebsocket, {
options: {
maxPayload: 1048576,
},
});
이제, 기존 mercurius 설정 부분 수정 및 websocket endpoint를 설정하겠다.
// 기존 mercurius 설정에 subscription: true 추가
app.register(mercurius, {
schema,
context: (req) => ({ prisma, req }),
graphiql: false,
subscription: true,
});
// 엔드포인트 추가
app.get('/', { websocket: true }, (connection) => {
connection.socket.on('message', () => {
connection.socket.send('ws connected');
});
});
그 다음, nexus를 통해 Subscription type을 지정하겠다.
필자는 아래와 같이 지정했다.
const Subscription = objectType({
name: 'Subscription',
definition(t) {
t.nonNull.field('notificationAdded', {
type: 'Notification',
args: {
userId: nonNull(intArg()),
},
resolve: async (_, { userId }, { pubsub }: Context) => await pubsub.subscribe(`NOTIFICATION_ADDED_${userId}`),
});
},
});
그리고 Subscription을 Schema에 추가한다.
const schemaWithoutPermissions = makeSchema({
types: [
Query,
Mutation,
Subscription,
// ...
],
// ...
});
이제, Mutation에 subscription을 publish 하는 코드를 추가하면 된다.
await context.pubsub.publish({
topic: `NOTIFICATION_ADDED_${userId}`,
payload: {
notification,
},
});
이제 설정이 모두 끝났다.
해당 코드를 deploy하고 클라이언트에서 테스트 해보면 정상 작동을 확인할 수 있다.