Search code examples
graphqlnext.jsapolloapollo-server

Next JS server side graphql subscriptions


I am currently building chat app in Next JS. I use graphql with Apollo Client in frontend and Apollo Server on backend. Now I want real time updates, but I found out there is no support for Subscription in apollo-server-micro. As they write here 😢 : https://www.apollographql.com/docs/apollo-server/data/subscriptions#enabling-subscriptions

Beginning in Apollo Server 3, subscriptions are not supported by the "batteries-included" apollo-server package. To enable subscriptions, you must first swap to the apollo-server-express package (or any other Apollo Server integration package that supports subscriptions).

But I can not use apollo-server-express because I use NextAuth for authentication and then I pass it to context:

export async function createContext({
  req,
  res,
}: {
  req: NextApiRequest;
  res: NextApiResponse;
}): Promise<Context> {
  const session = await getSession({ req });
  const user = { ...session?.user, _id: session?.userId } as User;
  const db = await dbConnect();
  return {
    user,
    db,
  };
}

Thanks for help 👍.


Solution

  • I found a solution, for everyone who wants to use graphql subscriptions on server:
    Use graphql-yoga instead : https://www.graphql-yoga.com/docs/features/subscriptions

    My code for pages/api/graphql.ts :

    import { createServer, createPubSub, PubSub } from "@graphql-yoga/node";
    import { NextApiRequest, NextApiResponse } from "next";
    import { Session } from "next-auth";
    import { getSession } from "next-auth/react";
    
    const pubSub = createPubSub<{
      "user:newMessage": [userId: string, message: Message];
      "user:newChat": [userId: string, chat: Chat];
    }>();
    
    export type pubSub = typeof pubSub;
    
    const server = createServer<
      {
        req: NextApiRequest;
        res: NextApiResponse;
      },
      {
        user: User;
        pubSub: any;
      }           
    >({
      context: async ({ req }) => {
        const session = await getSession({ req });
        await dbConnect();
        return {
          user: { ...session?.user, _id: session?.userId } as User,
          pubSub,
        };
      },
      schema: {
        typeDefs,
        resolvers: {
          Query,
          Mutation,
          Subscription,
        },
      },
    });
    
    export default server;