WebSocket connection to Hasura does not work with ApolloClient v3 on Node.js

Viewed 503

I created a Express/Node service which uses ApolloClient v3 to subscribe to a database on Hasura (database was created with Heroku on the Hasura platform). I want to subscribe to database changes with ApolloClient.

My ApolloClient setup looks like this (inspired by Split Communication Docs):

import express, { Request, Response } from "express";
import "cross-fetch/polyfill";
import ws from "ws";

import {
  ApolloClient,
  HttpLink,
  InMemoryCache,
  split,
  gql,
} from "@apollo/client/core";
import { WebSocketLink } from "@apollo/client/link/ws";
import { getMainDefinition } from "@apollo/client/utilities";

const app = express();
const port = 8080;

const httpLink = new HttpLink({
  uri: "https://my.hasura.app/v1/graphql",
  fetch,
});

const wsLink = new WebSocketLink({
  uri: "ws://my.hasura.app/v1/graphql",
  options: {
    reconnect: true,
  },
  webSocketImpl: ws,
});

const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === "OperationDefinition" &&
      definition.operation === "subscription"
    );
  },
  wsLink,
  httpLink
);

const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache(),
});

Things I already discovered for using ApolloClient with Node.js:

  • Use the "@apollo/client/core" import and not "@apollo/client", because this needs a react dependency (and i don't want that on my backend service)
  • import ws from "ws"; for a web socket implementation for node, as this is a Browser-Feature
  • import "cross-fetch/polyfill"; to have a fetch functionality, which is used by ApolloClient

Now the app runs without errors, but I don't know why my subscription is not working. I have the same code on the frontend (a little bit different, as it is React) and it works well there.

This is my subscription logic:

const observable = client.subscribe({
  query: gql`
    subscription {
      payments() {
        amount
        id
        time
        userId
      }
    }
  `,
});

observable.subscribe((data: any) => {
  console.log("data", data);
});

I am expecting that my console.log is logging some data, when the database changes - but it doesn't and my Hasura Dashboard lists no new connection. How can I establish a websocket connection to my database?

1 Answers

I discovered, that the WebSocket uri on a Node.js client has to start with http/https and not ws/wws.

With this code it works now:

const wsLink = new WebSocketLink({
  uri: "https://my.hasura.app/v1/graphql",  // instead of "ws://my.hasura.app/v1/graphql"
  options: {
    reconnect: true,
  },
  webSocketImpl: ws,
});
Related