0
votes

I'm trying to create a basic chat-like app just for the sake of learning a few things.

I have set up a basic graphql server to handle connecting a user, and let them add a message. Now I'm trying to add some mechanism so that every user can see each others' messages added in real time. I'm new to GraphQL but it would seem subscriptions are what I should use.

Here's my server index.ts:

import { createServer } from 'http';
import jwt from 'jsonwebtoken';
import mongoose from 'mongoose';
import resolvers from 'modules/resolvers';
import typeDefs from 'modules/type-defs';
import { ApolloServer } from 'apollo-server-express';
import cookieParser from 'cookie-parser';
import express from 'express';
import cors from 'cors';

const PORT = 4000;

const getUser = (token: string) => {
  // ...
};

const server = new ApolloServer({
  context: ({ req, res }) => {
    const token = req.cookies.jwt;
    const currentUser = getUser(token);

    return { currentUser, req, res };
  },
  resolvers,
  subscriptions: {
    onConnect: async (connectionParams, webSocket, context) => {
      console.log(`Subscription client connected using Apollo server's built-in SubscriptionServer.`)
    },
    onDisconnect: async (webSocket, context) => {
      console.log(`Subscription client disconnected.`)
    },
  },
  typeDefs,
});

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

app.use(cors({ credentials: true, origin: 'http://localhost:3000' }));
app.use(cookieParser());

server.applyMiddleware({ app, cors: false });
server.installSubscriptionHandlers(httpServer);

httpServer.listen(PORT, () => {
  console.log(`Server ready at http://localhost:${PORT}${server.graphqlPath}`);
  console.log(`Subscriptions ready at ws://localhost:${PORT}${server.subscriptionsPath}`);
});

mongoose.connect('mongodb://127.0.0.1:27017/irc', {
  useCreateIndex: true,
  useNewUrlParser: true,
  useUnifiedTopology: true,
});

What I'm trying to do is set up something as simple as possible on the client side (javascript/react) without having to rely on a lib like apollo-client. I managed to use simple fetch calls to send queries/mutations and was expecting to be able to use subscriptions in a "simple" way too. Apollo-client seems over complicated for what I'm trying to do and I'd like to understand how it actually works - but every tutorial on subscriptions seem to use this lib...

I don't really understand what my server is actually doing regarding subscriptions, and I thought I'd configured it to listen to websockets connections but I'm not so sure anymore.

I tried sending a basic message just to see what would happen:

const ws = new WebSocket('ws://localhost:4000/graphql');$
ws.onopen = event => {
  ws.send('Lorem ipsum dolor sit amet.');
};

... but even though my chrome's network tab seems to indicate that everything went fine, my server does not seem to care about my message since nothing gets logged.

Could someone please explain if it's possible to use basic web sockets to use apollo-server's subscriptions? And how?

Thanks

1

1 Answers

1
votes

Apollo Server and Apollo Client both use subscriptions-transport-ws under the hood to handle subscriptions. subscriptions-transport-ws uses WebSocket as a transport for exchanging messages between the server and the client. These messages have a specific format used by the library -- in order to use only WebSocket on the client-side, you'd have to send the same sort of messages.

You could inspect the source code to determine what sort of messages are being sent and when. The better option, though, would be to create an instance of SubscriptionClient and utilize its methods. Since usage of the library isn't particularly well documented, you'd have to stumble your way through but it should be possible.

If you're new to GraphQL, though, you should stick with Apollo Client since it's documentation is fairly good (see here) and subscriptions can be pretty complicated to set up, especially once you add authentication.