One of my side projects involves writing a GraphQL API around the Universal Chess Interface (UCI). I originally developed a mock implementation and wrote about it awhile back. That used version one of Apollo’s client/server stack, which changed quite a bit in version two. One of the biggest changes was the subscriptions interface and implementation, and I struggled for many hours to get that to work. Part of the problem is that the documentation is not very complete and rather scattered. This post will cover the most basic implementation of subscription service and the client code that uses it.
The GraphQL server will be based on ApolloServer, which in this case will use an Express server as middleware. Subscriptions will use a WebSocket that is attached to a plain HTTP server (also managed by ApolloServer, as we shall see).
There are two clients: the GraphQL Playground, and a client for use by Mocha to test the API outside of a GUI. For simplicity, I’ll keep the Mocha client code in the same folder as the server code. I also use Babel so I don’t have to think about Michael Jackson Scripts and the like.
With that in mind, here are the packages to be installed:
- apollo-link, apollo-link-http, apollo-link-ws, apollo-server-express
- babel-cli, babel-core, babel-preset-env
- graphql, graphql-tools
- mocha, chai
I’ll provide a link to a working code repository at the end of this article.
The server is as basic as I could make it:
On line 12 an ApolloServer is created, with a schema and resolver passed in. The applyMiddleware call on line 17 passes in the express application created on line 9. Finally, an http server is created to handle the web socket interface to the subscription service, which is created on line 22.
The schema is very basic: go will return a string acknowledgment, but behind the scenes it will fire off a method that sends publish notifications to subscribers. Subscribers subscribe through the info subscription API.
We can see how this works in resolvers.js:
I’ve made the resolvers deliberately simple. For example, the asyncIterator method from PubSub is quite sophisticated (it supports filters and authentication, for example). Since it is already well-documented, I won’t delve into various options here. All the resolver above does is to publish an infoTopic to all subscribers, passing info objects as the body of the subscription (line 10).
As I mentioned, I’ll use two clients for testing. One is the built-in Prisma Playground, a service automatically provided by the ApolloServer (FYI: you can turn this feature off in production).
Testing in Playground
To test, I’ll open Playground in Chrome, at http://localhost:3031/graphql. Within Playground you can open up multiple tabs. For the first, I’ll subscribe to the infoTopic:
When this command is played, you will see a ‘Listening …’ response in the right pane, as shown above. Now you’re subscribed.
Open another tab within Playground and query go:
This sends back a response of “going”, so everything is okay. Now, going back to the subscription tab, you will see the published output:
Testing using Mocha/Chai
There’s a lot of boilerplate in setting up a client, so I’ve created a utility file to handle query and subscribe operations. It’s called fetch.js:
The fetch.js code pulls in a lot of interdependent modules. For the test operations, I use apollo-link (line 6) to handle the interface between the server (which has to be running, btw 😉) and the tests’ GraphQL operations. There are actually two interfaces here: one to handle query and mutation requests vis HTTP (lines 21–27), and another that goes through a web socket to subscribe to a topic (lines 29–37).
Most of this comes from the documentation, but you will have to install a few additional modules I neglected to mention earlier:
- node-fetch (installed globally via npm -g)
The node-fetch module implements the HTTP Fetch API that’s becoming a standard. The ws module is a WebSocket implementation for Node (there are others), and gql is a template literal tag that you can read more about here.
The test itself is pretty straightforward: we first subscribe, then go:
The hander object (passed to the subscribe method on line 26) is what receives the publish notifications. When the last published message is received, the test process is terminated (line 15).
You should explore the links provided, as there is a lot more about GraphQL subscriptions that I wasn’t able to cover in this article. I’ve also included a few relevant links, below. A complete github repository containing the code above can be found here. Enjoy!
- Tutorial: GraphQL Subscriptions (server-side) — Apollo
- GraphQLapollographql/graphql-subscriptions: A small module that implements GraphQL subscriptions for Node.js
- SSL on Apollo Server 2.0 + Subscriptions · Issue #1338 ·
- apollographql/apollo-serverapollo-link-ws | Apollo Link
- Composable networking for GraphQL | Apollo Link
- Apollo Client | Apollo Client