Subscriptions/getting-started error server must support graphql-ws

Hello friends.

I try to realize the topic of Subscriptions in the documentation , by replacing the express server by createhandler in lambda (Getting Started with Subscriptions - Neo4j GraphQL Library)

import { createServer } from 'http';
import express from 'express';
import { ApolloServer, gql } from 'apollo-server-lambda';
import { WebSocketServer } from 'ws'; //ok1
import { useServer } from 'graphql-ws/lib/use/ws'; //ok2
import DatabaseManager from '../../services/database/DatabaseManager';
import { Neo4jGraphQL, Neo4jGraphQLSubscriptionsSingleInstancePlugin} from '@neo4j/graphql';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';


const typeDefs = gql`
type Movie {
  title: String!
  description: String!
}
`;

const driver = DatabaseManager.driver ;

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  driver,
  plugins: {
    subscriptions: new Neo4jGraphQLSubscriptionsSingleInstancePlugin(),
},})


const app = express();
const httpServer = createServer(app);

const wsServer = new WebSocketServer({
    server: httpServer,
    path: "/graphql"
});

  const initServer = () => {

  return neoSchema.getSchema().then(async (schema)=>{

    const serverCleanup = useServer({schema}, wsServer);

    const server = new ApolloServer({
      schema,
      plugins: [
          ApolloServerPluginDrainHttpServer({
              httpServer
          }),
          {
              async serverWillStart() {
                  return {
                      async drainServer() {
                          await serverCleanup.dispose();
                      },
                  };
              },
          },
      ],
  });

    const handlerMiddleware = server.createHandler()

    return handlerMiddleware
  })
}


export const handler = async (event:any, context: any, callback: any) => {
  const serverHandler = await initServer();

  return serverHandler({...event}, context, callback)
};

But when I try to realize Subscription in (Studio)

subscription MovieCreated($where: MovieSubscriptionWhere) {
  movieCreated(where: $where) {
    event
    timestamp
    createdMovie {
      title
      description
    }
  }
}

with variables:

{
  "where": {
    "title": "new film created"
  }
}

I have this error message : {
"message": "server must support graphql-ws or subscriptions-transport-ws protocol"
}

I don't understand why , could you help me please .

Hi Aymeric!

In your Javascript code of the server setup, please also apply the middleware like so:

    server.applyMiddleware({
        app
    });

(the server is the apollo server and app is the node.js express app + wsServer)

Please refer to the bottom part of the code snippet of the server setup in the Getting started with Subscriptions docs page

Hope this solves the issue!

Hi Thomas,

First of all I would like to thank you for the work done on the neo4j/graphql library. It is a pleasure to use it.

I have try to start express server and applyMiddleware, before createHandler and I meet two errors :

  • when I try :
await server.start()

//Error: When using an ApolloServer subclass from a serverless framework package, you don't need to call start(); just call createHandler().

  • and when I try :
server.applyMiddleware({app})

//Error: You must await server.start() before calling server.applyMiddleware()

I tried passing the server in the createdHandler with :

exports.handler = server.createHandler({
   expressAppFromMiddleware(middleware) {
     app.use(middleware);
     return app;
   }
});

With neo4j/graphql the resolvers are automatically created
But the result of the same subscription return:

{
"errors": [
{
"message": "Payload is undefined. Can't call subscriptions resolver directly.",
"rentals": [
{
"line": 2,
column: 3
}
],
"path": [
"movieCreated"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Payload is undefined. Can't call subscriptions resolver directly.",
" at subscriptionResolve (/Users/Aymeric/my-projects/node_modules/@neo4j/graphql/dist/schema/resolvers/subscriptions/subscribe.js:30:15)",
" at /Users/Aymeric/my-projects/node_modules/@neo4j/graphql/dist/schema/resolvers/wrapper.js:114:12",
" at field.resolve (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/utils/schemaInstrumentation.js:56:26)",
" at executeField (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:481:20)",
" at executeFields (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:413:20)",
" at executeOperation (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:358:14)",
" at execute (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:136:20)",
" at execute (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/requestPipeline.js:205:48)",
" at processGraphQLRequest (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/requestPipeline.js:148:34)",
" at processTicksAndRejections (internal/process/task_queues.js:95:5)",
" at async processHTTPRequest (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/runHttpQuery.js:221:30)"
]
}
}
}
],
"data": null

If you have an idea, I'll take any advice.

Hi again!
Could you share your entire, updated, server code snippet (again)? That would make it a bit easier to investigate/debug it.
Thanks!

Yes of course

import { createServer } from "http";
import express from "express";
import { ApolloServer, gql } from "apollo-server-lambda";
import { WebSocketServer } from "ws"; 
import { useServer } from "graphql-ws/lib/use/ws"; 
import DatabaseManager from "../../services/database/DatabaseManager";
import { Neo4jGraphQL, Neo4jGraphQLSubscriptionsSingleInstancePlugin } from "@neo4j/graphql";
import { ApolloServerPluginDrainHttpServer } from "apollo-server-core";

const typeDefs = gql`
  type Movie {
    title: String!
    description: String!
  }
`;

const driver = DatabaseManager.driver;

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  driver,
  plugins: {
    subscriptions: new Neo4jGraphQLSubscriptionsSingleInstancePlugin(),
  },
});

const app = express();
const httpServer = createServer(app);

const wsServer = new WebSocketServer({
  server: httpServer,
  path: "/graphql",
});

const initServer = () => {
  return neoSchema.getSchema().then(async (schema) => {
    const serverCleanup = useServer({ schema }, wsServer);

    const server = new ApolloServer({
      schema,
      context: ({ event }) => ({ req: { headers: event.headers } }),
      plugins: [
        ApolloServerPluginDrainHttpServer({
          httpServer,
        }),
        {
          async serverWillStart() {
            return {
              async drainServer() {
                await serverCleanup.dispose();
              },
            };
          },
        },
      ],
    });

    // If I try :
    //await server.start()
    //I have this error => //Error: When using an ApolloServer subclass from a serverless framework package, you don't need to call start(); just call createHandler().

    // If I try :
    //server.applyMiddleware({app})
    //I have this error => //Error: You must `await server.start()` before calling `server.applyMiddleware()`
// Then i try to use expressAppFromMiddleware() function to passed app server as middleware.


    const handlerMiddleware = server.createHandler({
      expressGetMiddlewareOptions: {
        cors: {
          origin: "*",
          credentials: true,
        },
      },
      expressAppFromMiddleware(middleware) {
        app.use(middleware);
        return app;
      },
    });

    return handlerMiddleware;
  });
};

export const handler = async (event: any, context: any, callback: any) => {
  const serverHandler = await initServer();

  return serverHandler({ ...event }, context, callback);
};

What error do you get in this situation?

In this situation, I have the same error :

{
“errors”: [
{
“message”: “Payload is undefined. Can’t call subscriptions resolver directly.”,
“rentals”: [
{
“line”: 2,
column: 3
}
],
“path”: [
“movieCreated”
],
“extensions”: {
“code”: “INTERNAL_SERVER_ERROR”,
“exception”: {
“stacktrace”: [
“Error: Payload is undefined. Can’t call subscriptions resolver directly.”,
" at subscriptionResolve (/Users/Aymeric/my-projects/node_modules/@neo4j/graphql/dist/schema/resolvers/subscriptions/subscribe.js:30:15)“,
" at /Users/Aymeric/my-projects/node_modules/@neo4j/graphql/dist/schema/resolvers/wrapper.js:114:12”,
" at field.resolve (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/utils/schemaInstrumentation.js:56:26)“,
" at executeField (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:481:20)”,
" at executeFields (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:413:20)“,
" at executeOperation (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:358:14)”,
" at execute (/Users/Aymeric/my-projects/node_modules/graphql/execution/execute.js:136:20)“,
" at execute (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/requestPipeline.js:205:48)”,
" at processGraphQLRequest (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/requestPipeline.js:148:34)“,
" at processTicksAndRejections (internal/process/task_queues.js:95:5)”,
" at async processHTTPRequest (/Users/Aymeric/my-projects/node_modules/apollo-server-core/dist/runHttpQuery.js:221:30)"
]
}
}
}
],
“data”: null