GraphQL Persisted Queries with Apollo Server 2

I know what you’re thinking, a third article on GraphQL persisted queries? What more could you possibly write about them. Well, the tech world moves fast, and the team over at Apollo is no exception. They’re doing big things over there, and it’s our responsibility to keep up. Apollo Server 2 removes a ton of boilerplate and significantly simplifies the set up process. Today, boys and girls, we’re going to delete some code.

If you haven’t read my previous post GraphQL Dynamic Persisted Queries, I suggest you start there, as this tutorial will pick up right where we left off. For those of you who are up to date with the idea of persisted queries and want to skip the previous article, you can find the project files here: source files.

No program is perfect, even the most talented engineers will write a bug or two (or three). By far the best design pattern available is simply writing less code. That’s the opportunity we have today, to accomplish our goals by doing less. If you’re following along, your GraphQL server’s package.json file should look something like this…

We no longer need most of these dependencies, time to trim the fat.

Let’s start by updating Apollo Server by running the following

npm install --save apollo-server-express@latest

This will uninstall Apollo Server 1 and install Apollo Server 2, at least until version 3 arrives. Apollo Server 2 comes with a ton of packages already built in. This removes boilerplate and reduces the number of steps we took to get set up in the beginning.

Go ahead and remove the following packages, as they are all included in Apollo Server 2.

npm uninstall cors body-parser graphql-tools graphql-playground-middleware-express graphql --save

That’s better, now our package.json file should look a little simpler.

Have you ever read an entire blog post about deleting code? I feel like we should do this more often.

Although not entirely necessary, Apollo does provide their own redis client called Apollo Server Cache Redis. However, we’ll stick with ioredis in this example. We’ll need to update our schemas.js file to include the gql tag. According to Apollo…

Apollo Server 2.0 ships with the gql tag for editor syntax highlighting and auto-formatting with Prettier. In the future, we will be using it for statically analyzing GraphQL queries, so Apollo Servers requires wrapping your schema with gql.

The gql tag parses the query string into an AST and can now be exported from the apollo-server-express package.

Seems like a small but significant change, as I for one love auto formatting. Last but not least, let’s update our server.js file. It’s mostly deletions, but a tiny bit of refactoring is needed.

So what changed? First we eliminated the cors and body-parser packages, both of which can now be passed as booleans to the new ApolloServer constructor from apollo-server-express. cors and body-parser both have a default value of true, technically it’s an (if not false) equality check, either way, we have no need to pass in those options here.

Next, we removed the graphqlExpress middleware from the old version of apollo-server-express, and playground from graphql-playground-middleware-express, which is now the default in-browser IDE instead of GraphiQL. We also removed the makeExecutableSchema utility function from graph-tools, as the new ApolloServer constructor will handle that work for us under the hood.

For our next trick, you’ll notice we completely removed our persistedQueries.js middleware import. This is no mistake, everything we wrote in the previous article to manage the sha256Hash in redis from scratch is now handled by Apollo Server 2, fresh out of the box, Ta-da! ApolloServer uses an LRU in-memory cache by default, so persisted query hashes can be processed and saved in-memory with little to no configuration.

In some cases this may be all we need, however, in our current setup, we’ll also need to pass in an object called persistedQueries to the ApolloServer constructor’s list of options. That object contains a property called cache whose value we can set to any in-memory database we need (e.g. redis). We can even provide our own custom variation as long as we follow the documented interface specified here by the apollo-server-caching package.

Snippet from the apollo-server-caching documentation on npm.

The signature for the set method is a little different in ioredis. We’ll need to make a small modification to the way we set our TTL’s if we want to adhere to theKeyValueCache interface specified above. Let’s create a file called enhancedRedis.js and add the following to it.

Since ioredis exports a constructor we can simply extend that class and make some slight changes. We are wrapping the set method with our own implementation that has the ability to set the TTL’s option in a configuration object. Then all we need to do is import our class instead, and pass enhancedRedis to the ApolloServer config object. Finally, after calling the ApolloServer constructor, we use the return value to call applyMiddleware. This is a required step when using a specific framework, in our case we pass in express.

Anytime we can remove over 100 lines of code and still accomplish our goals should be considered a win. At the very least, now you see why these changes deserved their very own blog post. Let’s fire up the app and make sure all is working as it should. Run the following commands, each in their own respective directory and terminal window.

Redis client


GraphQL server

node server.js

React client

npm run start

If your GET requests are succeeding but you don’t see hashes being saved in your redis database, that means your redis connection failed and Apollo server is using its built-in LRU cache to save the hash in-memory. To clear the LRU cache, stop and restart the GraphQL server.

Success! Now we have a lightweight implementation of persisted queries using Apollo Server 2. A few things worth mentioning, you may have noticed that we never removed express, even though Apollo Server 2 now comes with it’s own HTTP server built in. At some point, we may in fact no longer need express, but there is a bit more work to be done to solidify our edge caching setup. In the next article of this series, we’ll peruse some more advanced concepts, so it’ll behoove us to remain flexible. This goes for ramda as well, we’ll find a use for it soon.

A visual reminder of what we’ve accomplished so far.

Technically everything we went over in part 1 and part 2 was agnostic to whichever GraphQL Server middleware we chose. This article favors Apollo Server 2 as an example of what’s possible with the current version. We could just as easily roll back to our previous set up and switch out Apollo Server 2 with Express GraphQL, and all would work just as it should.

As always, if you had any trouble following along you can find the completed project files here. Source files.