1
votes

I've made a GraphQL backend using Apollo Server, Sequelize (for the ORM), MySQL (DB) and Express (Web Server).

I have also added subscriptions, which the problem is there. I can't even reach the WS endpoint using a websocket tester.

Can someone review my code and tell me what the problem is? I looked in the docs, other stackoverflow questions and I can't find any solution.

The code: https://github.com/seklyza/graphqlsubscriptions

Thanks for everyone

2

2 Answers

0
votes

I think you have to make 2 Servers one for the app which uses the express server and one for the websocket. It could look like this.

GraphQL express server:

...

graphQLServer = express();

const GRAPHQL_PORT = 4000;

graphQLServer.use('/graphql', bodyParser.json(), graphqlExpress((request) => {
  return {
    schema: executableSchema,
  };
}));

graphQLServer.use('/graphiql', graphiqlExpress({
  endpointURL: '/graphql',
}));

graphQLServer.listen(GRAPHQL_PORT, () => {
  console.log(`GraphQL Server is now running on http://localhost:${GRAPHQL_PORT}/graphql`); // eslint-disable-line no-console
});

...

websocket server for subscriptions:

...

const WS_PORT = 8080;

const websocketServer = createServer((request, response) => {
  response.writeHead(404);
  response.end();
});

websocketServer.listen(WS_PORT, () => console.log( // eslint-disable-line no-console
  `Websocket Server is now running on http://localhost:${WS_PORT}`
));

const subscriptionManager = new SubscriptionManager({
  schema: executableSchema,
  pubsub: pubsub,
  setupFunctions: { /* your subscription channels */ },
});

subscriptionServer = new SubscriptionServer({
  subscriptionManager: subscriptionManager
}, {
  server: websocketServer,
  path: '/',
});

...

And you need some sort of publication subscription service, we use pubSub. It is included in the server file and looks like this:

import {
  PubSub
} from 'graphql-subscriptions';

const pubsub = new PubSub();

export {
  pubsub
};
0
votes

You can create some web socket server wrapper which implements start method which will be responsible for creating and running the WSServer, as well as it will create a SubscriptionServer with use of SubscriptionManager

// in subscription.js
import { PubSub, SubscriptionManager } from 'graphql-subscriptions';

const pubSub = new PubSub();

let subscriptionManagerOptions = {
    schema: schema, // this is your graphql schema
    setupFunctions: {
        // here come your setup functions
    },
    pubSub: pubSub
};

const subscriptionManager = new SubscriptionManager(subscriptionManagerOptions);

export { pubSub, subscriptionManager };

After we have the subscriptionManager created, we can now implement the WSServer

import { createServer } from 'http';
import { SubscriptionServer } from 'subscription-transport-ws';
import { subscriptionManager } from './subscription';

const webSocketServerWrapper = {
    start: function(port){

        const webSocketServer = createServer((request, response) => {
            response.writeHead(404);
            response.end();
        });    

        webSocketServer.listen(port, () => {
            console.log('WSServer listening on port ' + port);
        });

        new SubscriptionServer({
            subscriptionManager,
            onSubscribe: (message, options, request) => {
                return Promise.resolve(Object.assign({}, options, {}));
            }
        }, webSocketServer);

    }
};

export default webSocketServerWrapper;

Now you can import the webSocketServerWrapper in the initialisation file like index.js and simply run webSocketServerWrapper.start(PORT);

Here, the second answer which I wrote, you can find a code responsible for creating example subscription and how it should be handled.