1

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

shabenda
  • 1,759
  • 3
  • 14
  • 23

2 Answers2

0

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
};
Locco0_0
  • 3,420
  • 5
  • 30
  • 42
  • I also did that using 2 servers which did not work. I will try again... – shabenda Mar 21 '17 at 10:01
  • By the way, how do I specify in GraphiQL the subscription server URL? – shabenda Mar 21 '17 at 10:07
  • Sorry i do not know how to specify the subscription server – Locco0_0 Mar 21 '17 at 10:09
  • It still doesn't work. I can't even connect to the WS server using a websocket client. Look at the new code at GitHub. – shabenda Mar 21 '17 at 10:48
  • Could you try to update the `subscriptions-transport-ws` package and use the `subscriptionServer = new SubscriptionServer({ subscriptionManager: subscriptionManager }, { server: websocketServer, path: '/', });` – Locco0_0 Mar 21 '17 at 10:52
  • Does the console log that the websocket server is running? Is the graph i QL running? – Locco0_0 Mar 21 '17 at 10:53
  • I updated the package, added the path, and yes, the console.log is working. But I still can't connect to the WS server (ws:// url). I think it is a problem in the subscriptions-transport-ws package. – shabenda Mar 21 '17 at 10:58
  • You could try to add an output to the `const wsServer = createServer((req, res) => { console.log("here"); res.writeHead(404); res.end(); })` and in the browser route to localhost:5000. If you see the output than youre connected. But of course cannot use that route because it returns `404` error – Locco0_0 Mar 21 '17 at 11:36
0

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.

Community
  • 1
  • 1
piotrbienias
  • 7,201
  • 1
  • 28
  • 33