Ways to activate subscriptions in type-graphql?

I'm encountering an issue with setting up subscriptions in my Apollo Server project using Express. Despite following all the steps outlined in the documentation [https://typegraphql.com/docs/subscriptions.html], I can't seem to get it working. Initially, I couldn't even listen for subscriptions, so I wrapped my Express app with an HTTP server and added a new subscription server within my app.listen function to enable listening. However, now when I try to trigger a subscription with a mutation, it doesn't work at all. I've tried various solutions found on Stack Overflow and GitHub without any success.

Below is a snippet of the server code:


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",
      }
    );
  });
};

If you notice any mistakes in my approach or can provide guidance on what I might be missing, please assist me in the right direction.

Answer №1

Here is a solution that should work:-

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 initializeApp = 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 }` );
    } );
};

initializeApp().catch( err => devLogger( err ) );

Answer №2

If you're looking to create a GraphQL server without importing SubscriptionServer from subscriptions-transport-ws, here is a template for a simple GraphQL server.

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({
      // Add your resolvers here
      resolvers: [],
      validate: false
    }),
    // Path customization for subscriptions (optional)
    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 functionality
  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: If your Typescript is not recognizing the file containing your subscription resolver, make sure to include the necessary paths in your tsconfig.json. Sometimes, auto imports by vscode can also update this configuration.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the correct way to trigger an event specified as a string parameter in the emit() function?

My current goal is to pass the emit name as a string (for example, 'showComponent') from child to parent. I then want to trigger another emit in the emitAction(callbackName: string) function, and finally execute the showComponent() function. I&a ...

Ways to Close a Modal in Ionic 5

I have a scenario where I need to open a modal, perform an asynchronous action, and then automatically dismiss the modal once the action is completed. Specifically, I want to use the fetchData function to handle the async task. @Component({ }) export cla ...

Angular: Unable to retrieve defined data when loading a component

There is a nagging question in my mind that I hesitate to ask because deep down, I know the answer is probably staring me in the face. After struggling with code for two days straight, I am on the brink of pulling my hair out. Although I am relatively new ...

Mastering the application of map, filter, and other functions in Angular using Observables

After creating this Observable: const numbers$:Observable<any>=Observable.create((observer)=>{ for(let i=0;i<5;i++) observer.next(i); }) I attempted to use map and filter as shown below: numbers$.pipe(map(x=>{x+110})).subscr ...

Ensuring Commitments in the ForEach Cycle (Typescript 2)

Having trouble with promise chains after uploading images to the server in Angular 2 and Typescript. Let's come up with some pseudo-code: uploadImages(images):Promise<any> { return new Promise((resolve, reject) => { for (let imag ...

What are some ways to condense this Angular/TS code for improved performance and readability?

I am in need of assistance with refactoring a method called getBaseUrl(). This method assigns a specified string value to this.baseURL based on the input serviceType. getBaseUrl(serviceType: string, network?: string) { // Method logic to determine base ...

Implementing Styled API in TypeScript with props: A Comprehensive Guide

I'm currently working on styling a component using the new styled API, not to be confused with StyleComponents. const FixedWidthCell = styled(TableCell)((props: { width: number }) => ({ width: props.width || 20, textAlign: "center", })) The i ...

How can I make TypeScript properly export function names for closure-compiler?

Here is the TypeScript code I am working with: namespace CompanyName.HtmlTools.Cookie { export function eraseCookie(name:string, path:string) { createCookie(name, "", path, -1); } export function readCookie(name:string) { ...

The issue arises when Jest ceases to function properly once the "type": "module" is configured in the tsconfig.json file

I have encountered an issue while using jest for unit testing in typescript. When I set "type": "module" in the tsconfig.json file, my app runs perfectly fine but jest stops working and displays a "ReferenceError: require is not defined". const { pathsToMo ...

Typescript sometimes struggles to definitively determine whether a property is null or not

interface A { id?: string } interface B { id: string } function test(a: A, b: A) { if (!a.id && !b.id) { return } let c: B = { id: a.id || b.id } } Check out the code on playground An error arises stating that 'objectI ...

Creating TypeScript versions of `delegate` pattern JavaScript code

Looking for a way to convert the following javascript code into typescript? const handlers = { say (msg) { console.log(msg) }, add (a, b) { return a + b } } function caller (method, ...args) { if (handlers[method]) return handlers[methd ...

Restricting the types within a generic union type in TypeScript

//Custom declaration: interface TickListFilter { type: "tickList"; value: string; } interface ColorFilter { type: "color" value: ColorValueType } type FilterType = TickListFilter | ColorFilter; ... updateValue = (filte ...

Mastering the integration of NestJS with Redis for microservices

Currently, I am diving into the world of nestjs microservices. I am curious, what commands are available for me to use? const pattern = { cmd: 'get' }; this.client.send<any>(pattern, data) Additionally, how do I go about retrieving data ...

Having trouble decoding a cookie received from a React.js front-end on an Express server

When using React js for my front end, I decided to set a cookie using the react-cookie package. After confirming that the request cookie is successfully being set, I moved on to configure the Express server with the cookie parser middleware. app.use(cookie ...

Classes in Typescript can implement interfaces to streamline the functionality

Recently, I've been working on creating my custom class called AxiosError and I can't help but feel like the code is a bit repetitive. //types.ts export interface IAxiosRequest{} export interface IAxiosResponse{} export interface IAxios ...

How can a class be imported into a Firebase Cloud function in order to reduce cold start time?

When optimizing cold start time for Firebase Cloud functions, it is recommended in this Firebase Tutorial to import modules only where necessary. But can you also import a class with its own dependencies inside a function? In my scenario, I need to use Bc ...

The issue with the tutorial is regarding the addHero function and determining the source of the new id

Whenever I need to introduce a new superhero character, I will utilize the add(string) function found in heroes/heroes.component.ts add(name: string): void { name = name.trim(); if (!name) { return; } this.heroService.addHero({ name } as H ...

Conflicts arise when trying to create several objects with different material types in ThreeJS within the

Adding a star to the scene caused all objects in the scene to turn white and the perspective of the objects to glitch. Switching the materialStar to new THREE.MeshBasicMaterial fixed the rendering issue. It appears that the problem stems from having multip ...

Tips for passing multiple items for the onselect event in a ng-multiselect-dropdown

I've got a multi-select dropdown with a long list of options. Currently, when I choose a single item, it triggers the Onselect event and adds data from the newArrayAfterProjectFilter array to the myDataList based on certain conditions in the OnselectE ...

Module augmentations do not allow for exports or export assignments

import { Request as ExpressRequest, Response as ExpressResponse } from 'express'; declare module 'kvl' { export = kvl; } declare const kvl: { ValidationDone:(param:(error: any, response: ExpressResponse) => void) => void; ...