I'm struggling with this all day long, I want to implement subscriptions feature on my mongodb-express-graphql-nextjs project. I can't use context.pubsub in resolver. Am I missing something? please save me!
Problem
Cannot use pubsub in subscription context.
comment.gql.js
export const resolvers = {
  Subscription: {
    commentAdded: {
      subscribe: (_, args, context) => {
        console.log(context) // <---------- Undefined
        return context.pubsub.asyncIterator('NEW_COMMENT')  
        // An Error occurred. cannot read property 'pubsub' in 'context
      },
    },
  },
  Query: {
      ... other operations work well
  }, 
  Mutation: {
      ... other operations work well
  }
}
What I've done
Apollo Server
import express from 'express'
import { ApolloServer } from '@apollo/server'
import { expressMiddleware } from '@apollo/server/express4'
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'
import { PubSub } from 'graphql-subscriptions'
import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress'
import cors from 'cors'
import cookieParser from 'cookie-parser'
import { json } from 'body-parser'
import http from 'http'
import schema from './controllers'
import { WebSocketServer } from 'ws'
import { useServer } from 'graphql-ws/lib/use/ws'
const startApolloServer = async () => {
  const pubsub = new PubSub()
  const app = express()
  const httpServer = http.createServer(app)
  // Create Web Socket
  const wsServer = new WebSocketServer({
    server: httpServer,
    path: '/graphql',
  })
  const serverCleanup = useServer({ schema }, wsServer)
  const apolloServer = new ApolloServer({
    schema,
    plugins: [
      ApolloServerPluginDrainHttpServer({ httpServer }),
      {
        async serverWillStart() {
          return {
            async drainServer() {
              await serverCleanup.dispose()
            },
          }
        },
      },
    ],
  })
  await apolloServer.start()
  app.use(cookieParser())
  app.use(express.static('public'))
  app.use(
    graphqlUploadExpress({
      maxFileSize: 1000000000, // 100 MB
      maxFiles: 10,
    })
  )
  // Specify the path where we'd like to mount our server
  app.use(
    '/graphql',
    cors(),
    json(),
    expressMiddleware(apolloServer, {
      context: async ({ req }) => ({ req, pubsub }), // <--- Here I put pubsub into context
    })
  )
  app.set('trust proxy', true)
  app.use('*', (req, res, next) => {
    next()
  })
  await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve))
  console.log(` Server ready at http://localhost:4000/graphql`)
}
const run = async () => {
  try {
    await startApolloServer()
  } catch (err) {
    console.log(err)
  }
}
run()
Apollo Client (Next.js)
import { useMemo } from 'react'
import { split, InMemoryCache, ApolloClient } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import { createUploadLink } from 'apollo-upload-client'
import getConfig from 'next/config'
import possibleTypes from './possibleTypes.json'
import fetch from 'isomorphic-fetch'
import { getToken } from './utils/auth'
import { GraphQLWsLink } from '@apollo/client/link/subscriptions'
import { createClient } from 'graphql-ws'
import { getMainDefinition } from '@apollo/client/utilities'
const { publicRuntimeConfig } = getConfig()
const { NODE_ENV } = publicRuntimeConfig
let apolloClient
const authLink = setContext((_, { headers }) => {
  // get the authentication token from cookie if it exists
  const token = getToken()
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : '',
    },
  }
})
const wsLink =
  typeof window !== 'undefined'
    ? new GraphQLWsLink(
        createClient({
          url: 'ws://localhost:4000/graphql',
        })
      )
    : null
const httpLink = createUploadLink({
  uri: NODE_ENV === 'development' ? 'http://localhost:4000/graphql' : 'https://coos.kr/graphql',
  headers: { 'apollo-require-preflight': 'true' },
  credentials: 'same-origin',
  fetch,
})
const splitLink =
  typeof window !== 'undefined' && wsLink != null
    ? split(
        ({ query }) => {
          const def = getMainDefinition(query)
          return def.kind === 'OperationDefinition' && def.operation === 'subscription'
        },
        wsLink,
        authLink.concat(httpLink)
      )
    : authLink.concat(httpLink)
function createApolloClient(initialState, ctx) {
  return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: splitLink,
    cache: new InMemoryCache({
      possibleTypes,
    }).restore(initialState),
    credentials: 'include',
  })
}
export function initializeApollo(initialState = null) {
  const _apolloClient = apolloClient ?? createApolloClient()
  if (initialState) {
    _apolloClient.cache.restore(initialState)
  }
  if (typeof window === 'undefined') return _apolloClient
  apolloClient = apolloClient ?? _apolloClient
  return apolloClient
}
export function useApollo(initialState) {
  const store = useMemo(() => initializeApollo(initialState), [initialState])
  return store
}
And below is my schema shape
import GraphQLUpload from 'graphql-upload/GraphQLUpload'
import { makeExecutableSchema } from '@graphql-tools/schema'
import { merge } from 'lodash'
import { typeDef as User, resolvers as userResolvers } from './user.gql'
import { typeDef as Post, resolvers as postResolvers } from './post.gql'
import { typeDef as Comment, resolvers as commentResolvers } from './comment.gql'
const rootTypeDef = `
  type Query {
    _empty: String
  }
  type Mutation {
    _empty: String
  }
  type Subscription {
    _empty: String
  }
  scalar Upload
`
export default makeExecutableSchema({
  typeDefs: [
    rootTypeDef,
    User,
    Post,
    Comment,
  ],
  resolvers: merge(
    { Upload: GraphQLUpload },
    userResolvers,
    postResolvers,
    commentResolvers,
  ),
})