Introducing GraphQL Cache

GraphQL Cache


See the project on GitHub


At StackShare, we’ve been experimenting with GraphQL for some of our new features. We’re using Apollo on the front end and GraphQL Ruby on the back end. Don’t worry, we’ll be publishing a full retrospective on why we chose GraphQL and how it is implemented soon.

We’ve encountered a couple of gaps in the Ruby GraphQL implementation. One of the biggest pieces missing from the gem is a clean means of implementing caching of resolved fields. GraphQL queries can get complicated - so much so that we have concepts like “max complexity” in our schema.

Of course you can implement it easy enough:

< 1.8

field :my_field, types.Int do
  resolve ->(obj, args, ctx) {
    Rails.cache.fetch([obj.id, 'my_field']) do
      # ... some long running calculation
    end
  }
end

> 1.8

field :my_field, Int

def my_field
  Rails.cache.fetch([obj.id, 'my_field']) do
    # ... some long running calculation
  end
end

But now we have to write a cache block and key in each resolver to be cached. This is a maintenance nightmare in terms of cache keys and is just plain ugly Ruby.

To combat these issues, we implemented a custom middleware for graphql-ruby that handles key construction and cache reads/writes transparently. Now when we want to cache a field, all we have to do is add a keyword parameter to the field:

field :my_field, Int, cache: true

The value is cached under a key that uniquely identifies this field for this object. After working with it for a while, we’ve decided to open-source our solution as graphql-cache. The gem is currently in pre-production release and only supports version 1.8.0 of the graphql-ruby gem, but we plan to add support for previous versions of both it and Rails.

Enjoy!