How to trigger subscriptions in type-graphql?

1.5k views Asked by At

I have a project set up with Apollo Server with express. I have been trying to set up subscriptions but it is just not happening. I have followed all the steps as per the following link :

https://typegraphql.com/docs/subscriptions.html

Further, I wasn't able to listen when I ran my subscription initially. So I wrapped my express app with an http server and in my app.listen, I added a new subscription server and then the subscription was listening. But now , when I run the mutation that is supposed to trigger the subscription, it doesn't get triggered. I have been trying a bunch of things and nothing on SO or Github has helped me so far.

The following is the code of the server


import express from "express";
import { ApolloServer } from "apollo-server-express";
import cors from "cors";
import { SubscriptionServer } from "subscriptions-transport-ws";
import { execute, subscribe } from "graphql";
import { createServer } from "http";

const main = () => {
  const app = express();

  app.use(
    cors({
      origin: "http://localhost:3000",
      credentials: true,
    })
  );
  const apolloServer = new ApolloServer({
    playground: {
      settings: {
        "request.credentials": "include",
      },
    },
    schema: await buildSchema({
      resolvers: [Resolver1, Resolver2, Resolver3],
      validate: false,
    }),
    context: ({ req, res }) => ({ req, res, redis }),
  });

  apolloServer.applyMiddleware({
    app,
    cors: false,
  });

  const server = createServer(app);

  server.listen(4000, async () => {
    console.log("Server running on port 4000");
    new SubscriptionServer(
      {
        execute,
        subscribe,
        schema: await buildSchema({
          resolvers: [Resolver1, Resolver2, Resolver3],
          validate: false,
        }),
      },
      {
        server,
        path: "/graphql",
      }
    );
  });
};

Please let me know if I'm doing anything wrong or guide me in the right direction.

2

There are 2 answers

0
Aman Bhardwaj On

This should do:-

import 'reflect-metadata';
import express from 'express';
import { ApolloServer } from 'apollo-server-express';
import { devLogger } from './utils/constants';
import { createServer } from 'http';
import { getSchema } from './utils/schema';

const main = async () =>
{
    const app = express();
    const ws = createServer( app );
    const apolloServer = new ApolloServer( {
        schema: await getSchema(),

    } );

    apolloServer.applyMiddleware( { app } );
    apolloServer.installSubscriptionHandlers( ws );

    const PORT = process.env.PORT || 5000;
    ws.listen( PORT, async () =>
    {
        devLogger( `Server started on port ${ PORT }` );
    } );
};

main().catch( err => devLogger( err ) );
0
wc203 On

You don't need to import SubscriptionServer from subscriptions-transport-ws. Here is a simple GraphQL server template for you.

server.ts

import "reflect-metadata";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import { buildSchema } from "type-graphql";
import http from 'http';

const main = async () => {
  const app = express();
  const httpServer = http.createServer(app)

  const apolloServer = new ApolloServer({
    schema: await buildSchema({
      // Insert your resolvers here
      resolvers: [],
      validate: false
    }),
    // Not required but if you want to change your path do it here. The default path is graphql if "subscriptions" field is not passed
    subscriptions: {
      path: "/subscriptions",
      onConnect: () => console.log("Client connected for subscriptions"),
      onDisconnect: () => console.log("Client disconnected from subscriptions")
    }
  });

  apolloServer.applyMiddleware({ app, cors: false });
  apolloServer.installSubscriptionHandlers(httpServer)

  httpServer.listen(4000, () => console.log("Server ready at http://localhost:4000"))
};

main().catch((err) => console.error(err));

resolver

import {
  Arg,
  Mutation,
  Resolver,
  Root,

  // Required for subscription to work
  Subscription, 
  PubSub,
  PubSubEngine
} from "type-graphql";

@Resolver()
export class MessageResolver {
  @Subscription({ topics: 'NOTIFICATIONS' })
  newNotification(@Root() payload: string) : string {
    return payload
  }

  @Mutation(() => String)
  async sendMessage(
    @Arg('name') name: string,
    @PubSub() pubsub: PubSubEngine
  ): Promise<string> {
    pubsub.publish('NOTIFICATIONS', name)
    return name
  }
}

Note To answer your question, it's highly likely that Typescript isn't reading the file where you wrote your subscription resolver, resulting in no GraphQL schema being created. Be sure to add the following lines to your tsconfig.json file. Sometimes, vscode auto imports paths and add them to this line.

  "include": [
    "./src/**/*.tsx",
    "./src/**/*.ts"
  ]