FilamentQL - A GraphQL Caching Library

Nelson Wu
The Startup
Published in
6 min readNov 12, 2020

Contributing Authors:

Andrew Lovato, Chan Young Choi, and Duy Nguyen

GraphQL is growing

GraphQL is a query language for APIs. It is not only incredibly powerful (in terms of its very efficient data queries) but it is growing increasingly more popular over the years as a recent 2019 State of Javascript has shown that a little over half of all Javascript developers are interested in learning about GraphQL.

Majority of all JS developers have at least heard of or are interested in learning more about GraphQL!

GraphQL caching and Filament

However, GraphQL is a only a spec. In short, it gives us certain rules to adhere to in terms of how we draft queries, define schemas, and validate GraphQL syntax. It is not highly opinionated in this regard, as any additional features or implementations of the language is open to the creative liberties of the developer. Caching data for quick, future access is one such feature.

What is caching an why is it important? Imagine the client has made a request for data about a person’s name and email:

query {
person {
name
email
}
}

Now suppose we make subsequent requests for the person’s name. If we had stored our prior requests in cache, we could avoid unnecessary and expensive refetching of data from our server.

In addition, imagine we had made a query for the person’s name but instead of their email we want their age.

query {
person {
name
age
}
}

If we had their name stored, we would instead query for just the age, and the client would only download newly requested data and then gather and combine any previously requested data from local cache. Although for this particular example it may be trivial for the user to make a redundant request to the server and download data like name again, you could imagine for far more complex and larger queries, the amount of data overhead would be enormous for repeated query requests.

This is especially important for mobile users. As roughly a third of all Americans and a majority of millennials use a phone as their primary internet browsing device, it is increasingly more important to reduce the amount of data overhead. A GraphQL caching implementation will reduce the amount of network requests and roundtrips, which will ultimately save time and bandwidth for mobile users.

FilamentQL attempts to solve this problem through a seamless and easy to implement caching layer that is both fast and consistent.

How Filament works

FilamentQL provides both a server-side caching solution and client-side caching solution. In addition, FilamentQL also abstracts the code for sending queries and mutations to the server and automatically updates the state when the data is returned.

On the server-side, FilamentQL provides a GraphQL endpoint for your Express server with user-defined type definitions and resolvers, and creates a caching layer via a local Redis instance. When a client makes a request, FilamentQL checks the Redis cache for any previously stored data that matches the request. Through a parsing algorithm, FilamentQL then takes the incoming query and identifies any dissimilarities, and makes a subsequent query for just those dissimilarities to the database. Whenever possible, FilamentQL merges data coming back from the database with data from Redis cache and sends it back to the client:

FilamentQL server-side caching

On the client-side, FilamentQL behaves similarly. For its local cache implementation, FilamentQL utilizes session storage, a built-in property on the browser’s window object, which allows data to persist throughout page refreshes.

FilamentQL client-side caching

How FilamentQL parses incoming queries

FilamentQL’s parsing algorithm works recursively to isolate key pieces of information within a GraphQL query. There are numerous helper functions to aid in this goal. The initial index, beginning at 0, is incremented and its current location is carefully studied. If the algorithm decides that it has found a predefined structure, it stores it in a meaningful way for later use.

One of the reasons why GraphQL is so dynamic is because there are many ways a query can be structured and formed. FilamentQL’s parsing algorithm aims to account for these variations. If the algorithm finds a piece of data in the cache, it is then stored within an object; and each piece of information found thereafter is then added to that stored object, property by property until the object is built out in the shape of the original query. If data is not found in the cache, the field or sub-field is added to the new query string. Fields and sub-fields are distinguished as well as variables. The algorithm, upon finding a variable, will seek the location of that variable and the specific field whose sub-fields it is meant to modify. Ending curly braces are accounted for using a simple counter: as opening brackets are added, the counter is incremented; as closing brackets are added, the counter is decremented. The function determines that the query has been parsed when the final curly brace has been closed.

One of the most important things that the algorithm has to distinguish is the difference between a field and sub-field. A field will have an opening curly brace after it while a sub-field will not. The solution is to nest a subset of data from the cache and check for properties on that object as those properties would have to be present on all objects as all would be updated in any response-cache merge. Every time the algorithm finds a field, it nests that object deeper.

The data is automatically normalized in the cache as our storage system isolates by query field. It does not simply store all responses. It always updates the data that is already there according to what is returned.The algorithm accounts for a variable object with a single property, named operations, queries defined with the query keyword, and queries written without one; i.e., beginning with the field itself.

Offline Mode

FilamentQL also supports an offline mode feature. If the user gets disconnected from the server, all mutations made when the internet is down will be stored in a queue. At a set interval, FilamentQL checks if the network is back online. Whenever the user is back online, FilamentQL dequeues and sends each mutation to the server. Subsequently, the data that comes back from server will update the state and re-render the frontend components. What the user experiences and sees on their end is a seamless re-syncing of information when they come back online.

FilamentQL’s Future Roadmap

FilamentQL is a fresh and new open source project developed by a team of passionate developers in collaboration with OSLabs. FilamentQL’s Github can be found here and welcomes feedback, stars, and suggestions.

As FilamentQL is on its early legs of development, it currently supports queries with variables, but not aliases, fragments, or directives. However, support and development for more robust queries is next on the list for FilamentQL’s future roadmap.

--

--