StashQL: Efficiently Update and Cache Your GraphQL Queries

Hakudo Ueno
5 min readApr 14, 2022

--

StashQL is an npm package that is used for caching GraphQL queries and data with additional options to update the cache as compared to traditional packages.

Built with OS Labs Tech Accelerator, StashQL is an npm package that is used for caching GraphQL queries and data with additional options to update the cache, compared to your traditional packages.

Background (GraphQL vs REST API)

REST API(also known as RESTful API) has long been the standard for designing web APIs. However, that doesn’t mean it’s perfect. REST API is arranged in terms of endpoints and in order to receive data, users may need to hit multiple endpoints, leading to issues with over and under-fetching of data. On the other hand, GraphQL is a query language that gives the user the ability to get exactly what they want when fetching data, while only requiring the use of one request/endpoint. Recently, GraphQL has gained significant traction and popularity due to its fast, flexible, and efficient API calls. But that does not mean it is without pitfalls. When compared to the traditional RESTful architecture, server-side caching is still a challenge in GraphQL. REST API gives users the ability to cache responses by putting an optional key in the header of the request. This feature allows REST API to store frequently requested data to the client in stored memory rather than querying the database again, improving response time. GraphQL itself does not have caching features built-in but instead relies on third-party packages and libraries. One of the problems with these outside packages is that they have no flexibility on how the cache is being updated. Here’s where StashQL enters the picture.

StashQL

StashQL provides GraphQL users with an effortless way to cache their data and customize how the data gets updated in the cache when a mutation occurs in the database. Additionally, StashQL logs what queries and mutations were executed, the data received back from the database (or errors), and the run time of each query/mutation. The logged information can be accessed directly from the logs folder created by StashQL or through StashQL’s CLI.

StashQL can be installed by typing:

npm install stashql

After installing, a user can create a new instance of the StashQL class, which will require the user to pass in their GraphQL schema and Redis cache, and an optional third integer parameter to set the Time to Live(TTL) of the cached data.

const StashQL = new stashql(schema, redisCache, 100)

Users can then utilize the new instance of StashQL and its built-in methods as traditional middleware functions.

app.use('/graphql', StashQL.queryHandler, (req, res) => {
return res.status(200).json(res.locals.data);
})

When sending GraphQL queries or mutations, users should use the StashQL’s queryHandler() method. Upon running a query for the first time, the queryHandler() method will run the query as normal and then cache the query along with the returned data into the user’s Redis cache. If the query is already stored in the cache, the queryHandler() method will simply retrieve the data from the cache, avoiding unnecessary trips to the database. If the cache needs to be cleared, StashQL also offers the clearCache() method which will flush all the cached data

What about when a mutation occurs in the database? StashQL provides two methods, the refillCache and clearRelatedFields methods, to update the user’s cache so that they never have to worry about stale data being returned from their queries. Both of these methods can be passed in as optional arguments in a user’s GraphQL mutation types.

The refillCache argument will take in a string value, which will be any field the user wants to update after running a mutation. The queryHandler() method will see this argument, take its string value, and update any cached data relevant to the passed-in string value by re-running their corresponding queries to get the most up-to-date information from the database.

mutation{
addAuthor ( name:"John Smith", refillCache:"authors"){
name
}
}

Similar to the refillCache argument, the clearRelatedFields argument will also take in a string value which will be any field the user wants to update after a mutation. Upon seeing this argument, instead of updating the cached data relevant to the passed-in string by re-running their corresponding queries, the queryHandler() method will clear the relevant data from the cache.

exampleQuery =
`
query{
author{
name
}
}
`
mutation{
addAuthor(name:"John Smith", refillCache:exampleQuery){
name
}
}

Now when should you use the refillCache argument or the clearRelatedFields argument? We’ll explain their different use cases below.

A user should use refillCache if they’re running a mutation and they only have a few queries in their cache that deal with the field passed in. Since this method will re-run all queries in the user’s cache that correspond with the field passed in, multiple network requests may occur at once (in order to re-run queries and get the most up-to-date data). It is important to note that using this method could result in overloading a database or even database failure if the cache contains too many data that correspond with the passed-in field.

Scenario 1: Assume a user only has a small amount of cached data about authors in their database. Now let’s assume the user wants to add an author to their database, but wants to ensure that they won’t receive stale data from their cache when querying for any data related to authors. This user should consider passing in the refillCache method and a value of ‘authors’. This will re-run any cached queries that deal with authors and update the corresponding cached data.

If a user is executing a mutation that would affect a significant amount of cached data, they should consider passing in the clearRelatedFields argument. Upon seeing the clearRelatedFields argument, StashQL will take the passed-in field, look for any cached data that correspond to that field, and flush it from the cache. Now the next time a query is run, it will go to the database, send back the updated data, and then cache it. This avoids making multiple network requests and significantly reduces the possibility of overloading a database.

Scenario 2: say a user has a large amount of cached data about authors in their database. Now let’s assume the user wants to add an author to their database but wants to ensure that they won’t receive stale data from their cache when querying for any data related to authors. In this case the user should consider passing in the clearRelatedFields argument and a value of ‘authors’. This will clear any cached data relevant to authors so that the next time the user runs a query for author data, it will simply re-run ONLY that query instead of ALL queries that deal with authors.

What’s next for StashQL?

Currently, StashQL’s CLI only allows users to view and clear all logs. However, the StashQL team plans to improve and expand on this in the near future. We plan to give users more options on how they can log, retrieve, visualize, and download the data. We also plan to add new methods that will further enhance StashQL’s caching and mutation features.

Thank you all for taking the time to learn about our open-source tool.

StashQL: WebsiteGitHubnpmTwitter

Want to connect? Here’s our team:

Hakudo Ueno: GitHub LinkedIn

Simon Chen: GitHub LinkedIn

Ian Madden: GitHubLinkedIn

Louie Mendez: GitHubLinkedIn

--

--