enisdenjo / graphql-ws

Coherent, zero-dependency, lazy, simple, GraphQL over WebSocket Protocol compliant server and client.
https://the-guild.dev/graphql/ws
MIT License
1.75k stars 162 forks source link

Subscriptions not working with Hasura via apollo Client graphql. error - Error: WebSocket implementation missing; #513

Closed Albosonic closed 1 year ago

Albosonic commented 1 year ago

Screenshot Visualising is always helpful.

Screenshot 2023-10-19 at 10 20 32 AM

Expected Behaviour I added GraphQLWsLink to my apollo client. In order to support graphql subscriptions via Hasura back end. Yet I cannot get it to work properly. I followed all of the documentation and then some. This is the closest I have gotten with my implementation. Below

the biggest red flag is that it seems to get stuck in this error state until I remove split() then re implement, and it works kinda intermittently, but never surfaces data via the subscripttion

Actual Behaviour Sometimes I can get the ws handshake to happen in the browser network tab. But no data is present. At that point I added the "use client" tag to my component, figuring that web sockets only work client side. Then I start getting this error. I then tried adding WebSocketImpl: WebSocket({...}) and I just get more errors. Been running in circles for 2 days following error messages with no luck.

Debug Information


import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache, split } from '@apollo/client';
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
import { setContext } from '@apollo/client/link/context';
import { getMainDefinition } from '@apollo/client/utilities';

const httpLink = createHttpLink({
  uri: process.env.NEXT_PUBLIC_HASURA_LINK,
});

const wsLink = new GraphQLWsLink(createClient({url: process.env.NEXT_PUBLIC_HASURA_WSS_LINK}));

const hasuralink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      "Content-Type": "application/json",
      "X-Hasura-Admin-Secret": process.env.NEXT_PUBLIC_HASURA_SECRET,
    },
  }
});

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

const cache = new InMemoryCache();

const client = new ApolloClient({
  // Provide required constructor fields
  cache: cache,
  link: splitLink,
  name: 'yachty-apollo-client',
  queryDeduplication: true,
});

export default client;

Further Information Anything else you might find helpful.


{
  "name": "yachty",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "concurrently \"next dev\" \"node api-server\"",
    "dev:https": "next-dev-https --https --qr --port 4430",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@apollo/client": "^3.8.6",
    "@auth0/nextjs-auth0": "^2.2.2",
    "@aws-sdk/client-s3": "^3.391.0",
    "@emotion/react": "^11.10.6",
    "@emotion/styled": "^11.10.6",
    "@fontsource/roboto": "^4.5.8",
    "@mui/icons-material": "^5.11.11",
    "@mui/material": "^5.11.12",
    "@mui/x-date-pickers": "^6.16.0",
    "@reduxjs/toolkit": "^1.9.3",
    "concurrently": "^7.6.0",
    "cors": "^2.8.5",
    "dayjs": "^1.11.10",
    "dotenv": "^16.0.3",
    "express": "^4.18.2",
    "express-jwt": "^8.4.1",
    "graphql": "^16.6.0",
    "graphql-ws": "^5.14.1",
    "helmet": "^6.0.1",
    "jwks-rsa": "^3.0.1",
    "lodash": "^4.17.21",
    "morgan": "^1.10.0",
    "next": "13.2.3",
    "next-dev-https": "^0.1.1",
    "next-redux-wrapper": "^8.1.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-image-file-resizer": "^0.4.8",
    "react-redux": "^8.0.5",
    "redux-persist": "^6.0.0",
    "uuid": "^9.0.0",
    "uuid4": "^2.0.3"
  }
}
Albosonic commented 1 year ago

I went with polling, because this doesn't seem ready for prime time with my stack. Feel free to close if you want. I will switch back to WS when it's ready.