단, 오늘 예제로 사용되는 graphql-subscriptions은 일종의 데모 버전으로 하나의 서버로만 운영할 수 있음, 대규모 서버를 구축할 시 redis등을 유료로 사용해야 함
npm i graphql-subscriptions
//app.module.ts
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
installSubscriptionHandlers: true,
}),
installSubscriptionHandlers: true
: 웹소켓을 사용할 수 있게 해준다//common.module.ts
import { Global, Module } from '@nestjs/common';
import { PubSub } from 'graphql-subscriptions';
import { PUB_SUB } from './common.constants';
@Global()
@Module({
//! 특정 클래스를 전역으로 사용 -> exports해줘야 함
providers: [
{
provide: PUB_SUB,
useValue: new PubSub(),
},
],
exports: [PUB_SUB],
})
export class CommonModule {}
//orders.resolver.ts
@Subscription((returns) => Order)
pendingOrders() {
return this.pubSub.asyncIterator(NEW_PENDING_ORDER);
}
@Subscription
데코레이터로 구독을 만든다asyncIterator
에서 NEW_PENDING_ORDER을 구독(subscription)한다//oderes.service.ts
async updateOrders () {
...
await this.pubSub.publish(NEW_PENDING_ORDER, {
pendingOrders: { order, ownerId },
});
...
}
@Subscription((returns) => Order, {
filter: (payload, variables, context) => {
return payload.pendigOrders.ownerId === context.user.id;
},
resolve: ({ pendigOrders: { order } }) => `${order.id}님의 주문이 업데이트 되었습니다`,
})
pendingOrders() {
return this.pubSub.asyncIterator(NEW_PENDING_ORDER);
}
payload
: publish될 때 전달되는 값이 담겨있다.varialbes
: subscription한 resolver가 요청할 때 전달되는 값이 담겨있다.context
: NestJS의 네트워크 통신시 생겨나는 컨텍스트에 접근할 수 있다(http, ws)//app.module.ts
subscriptions: {
'subscriptions-transport-ws': {
onConnect: (connectionParams) => {
const token = connectionParams[TOKEN_KEY];
return { token };
},
},
},
context: ({ req, connection }) => {
return {
token: req ? req.headers[TOKEN_KEY] : connection.context[TOKEN_KEY],
};
},
}),