WPGraphQL Smart Cache with Next.js and Apollo

Francis Agulto Avatar

·

In this article, I will discuss the WPGraphQL SmartCache plugin, its main features, what problems it solves and how to use it with a Next.js frontend and the Apollo client. Essentially, you can use any front-end framework of your choice since the Smart Cache plugin is configured to work with all of them.

This will be a higher-level overview of the plugin. A deeper dive into all its features and capabilities are discussed in its repository in the readme file.

If you do want to follow along in this blog post, you will need the following prerequisites:

WPGraphQL/GraphQL

Before we dive into the cache, we need to understand what WPGraphQL and GraphQL are.  GraphQL is an open-source data query and manipulation language for APIs, and a runtime for fulfilling queries with existing data.  In other words, it takes any database and throws a schema on it that exposes it visually as a  graph which makes your data descriptions easy to understand.

The image below is an example of this in WordPress with the WP data being exposed in a schema and being able to ask for exactly what you want and getting it back in the exact shape.

WPGraphQL is also optimized for performance using the DataLoader method and other techniques as discussed on wpgraphql.com   However, there are still issues you can run into.

Over-Queries to WordPress and Fresh Data

As stoked as I am on WPGraphQL, it has some common issues when developers use it to decouple WordPress.   

Anytime you make a request to the WordPress backend via WPGraphQL, there is a cost you will pay to make that request performance-wise.  If you query WordPress too much, you will timeout your WordPress server.  There are ways around this, especially when using Next.js which I discuss here.

The other issue that is a general difficulty in web development is invalidating the cache to get fresh, up-to-date data and then making it performant for speed.

Thanks to the WPGraphQL Smart Cache plugin, we now have a solution for these common issues.

WPGraphQL SmartCache

WPGraphQL SmartCache is the latest plugin in the WPGraphQL ecosystem that allows you to cache your GraphQL requests from WordPress.  Once they are cached, they do not hit the WordPress server, they hit WPGraphQL SmartCache.  This way, you get better performance and use fewer resources on the WordPress end! Stoked! 🎉

The plugin is engineered so that it works specifically with your WordPress hosting platform’s network caching layer. Of course, the plugin’s first integration support is with WP Engine’s cache layer which is Varnish.

For now, just to clarify, 3 features that will work currently on any hosting platform that we are about to dive into in this article are:

  • Object Cache
  • Persisted Queries
  • Cache Invalidation

Host Specific supported features:

  • Network Cache (Varnish in WP Engine’s case)
  • And all of the above of course on any host-supported features

The network cache and cache invalidation will only work on supported hosts, but there are still benefits for sites on any host as stated.

I have an account on WP Engine with the plugins I need to make this work as stated at the beginning of the article on my WP install. Let’s dive into the features now of the plugin!

Cache Miss/Cache Hit

If you publish a post that’s brand new, you want that to be updated right away. When you update it, this will be a cache miss because the actual WordPress server will run those queries. WPGraphQL SmartCache understands what query was executed and then it determines what actions it should listen to within that new data action, in order to make the query.

Let’s see this in action in an image here with our dev console open in my browser once I visit the URL for the GraphQL query. The URL I am hitting is https://buddydemo1.wpengine.com/graphql?query={posts{nodes{title}}} (Note that I am using a browser that is not authenticated to my WordPress site):

This query is simple. I am asking for all my post titles, utilizing the HTTP GET method. In order to maximize the optimizations of the Smart Cache plugin, I am using GET. Since this is a brand-new request, it will be a cache miss as shown.

*** ⚠️ Just a note, if you must use POST requests which is not the recommended method, please see Object Cache in the readme for more information on how to enable this ***

After the initial cache miss, every subsequent request of this query is cached on WP Engine with SmartCache to optimize the speed ( image shows 36 ms! 🚅) and performance of your GraphQL query without hitting your WordPress server. This is just being served from the cache!! See the images below:

Cache Invalidation

Two of the hardest things in web development are cache invalidation and naming things. Most developers will tell you that. Let’s see how cache invalidation works in WPGraphQL SmartCache. In this image, look at the first post title:

My title has 2 exclamation marks. Let’s change that data in our WP Admin and see what happens.

I changed my first post title. You can see that it reflects in the JSON as well the headers. WPGraphQL SmartCache listened to the event change in WordPress, realized that it was a data change, and invalidates the cache allowing WordPress to serve accurate data. Cache Miss Stoke! The response time for this miss was 479ms

After the cache is invalidated due to the update, the request and query are now cached and every request from then on will not hit your WordPress server. This takes advantage of the network cache layer and gets accurate data upon changes.

This is such a game-changer, allowing developers to offset the responsibility of toiling with cache invalidation to the Smart Cache plugin! Jamstoked indeed! 😄 🕺🏾

Persisted Queries

A persisted query is a query string that is cached on the server side, along with a unique identifier. Clients can send this identifier instead of the corresponding query string, thus reducing request sizes dramatically (response sizes are unaffected). This is a major benefit of using persisted queries since large queries can become bottlenecks for client performance.

WPGraphQL Smart Cache provides support for persisted queries and can be used seamlessly with Apollo Persisted Queries Link. This also can be done on any hosting provider as well via POST request.

Let’s see how this feature works. In your WP Admin, go to the left hamburger menu and find GraphQL. Once there, navigate to Settings > Saved Queries. You should see an option to “Display saved query in documents in admin editor” as shown. Check that box:

When you check that box, you will see a new post type in the sidebar menu called GraphQL Documents:

This is a familiar editing UI now, just like how you edit posts, but in this case, it is your GraphQL document. There are a few ways you can identify your unique persisted query. Let’s do Alias Names for this example.

The first step is to go to my GraphiQL IDE and grab a copy the query I created to grab all my posts titles.

Once I have copied my query, the second step is to navigate back to GraphQL Documents post type, click on edit, and start filling out the fields.

The first field is the title field which I named “Get Post Titles.” You can name it anything you like, whether it is the actual operation name of the document or something that will remind you of what this query document does.

The second field is the actual document field of what the query string is in an JSON object. This query string is asking for all post titles.

Lastly, there is a description field to add any description you prefer for your own reference.

WPGraphQL Smart Cache gives each of your individual GraphQL documents an Alias Name or ID as you can see on the right-hand side of the image on the menu. We will manually change this default Query ID to the name of our choosing. (naming things is so hard in software engineering 😂) In this case, getPostsTitles. Once I fill that field in and click add, it will add that name to this document:

Stoked!!! Now let’s go back to the browser, and change the end of our original URL at the beginning of this article to our Alias Name as the value which will be getPostsTitles and execute to see if it works:

It worked!! Instead of the object, I had in there, the Alias Name we made manually works the same. We now have this document persisted on our server and reduced an upload cost as well as avoiding a long query string with our Alias Name! 🚀

This was just a snippet of what you can do with persisted queries on WPGraphQL Smart Cache. I encourage you to dive into all of it on the readme and repo.

Usage with Next.js, Apollo, and ISR

We enabled some key features on our WP Engine install with WPGraphQL Smart Cache. The last thing we need to do to make this come together is to consume that WordPress data on our front end. Let’s use Next.js and its hybrid rendering pattern, ISR with the Apollo Client.

If you want to follow along with the front-end side of things, you can clone my repository here.

Apollo Client Configuration

In my frontend code, I am using the Apollo GraphQL client to optimize its features to grab the data on the client. WPGraphQL Smart Cache plays nicely with Apollo and in this example, this is the code for my apollo.js file in the lib folder:

import {
  ApolloClient,
  ApolloLink,
  HttpLink,
  InMemoryCache,
} from "@apollo/client";

const link = ApolloLink.from([
  new HttpLink({
    uri: `${process.env.NEXT_PUBLIC_WORDPRESS_API_URL}/graphql`,
    useGETForQueries: true,
  }),
]);

export const client = new ApolloClient({
  link,
  cache: new InMemoryCache(),
  defaultOptions: {
    query: {
      fetchPolicy: "network-only",
    },
  },
});

Code language: JavaScript (javascript)

The first const is setting our link as ApolloLink. We set this as the HTTP link to process the graphql endpoint from WordPress which contains our data. Then, we put a key to use the useGETForQueries constructor as a fetch option because we want that for optimal performance on the Smart Cache plugin.

The second const is exporting the Apollo Client, and configuring it as "network-only" so that it becomes a fetch mechanism exclusively with the cache being now handled by varnish and WP Engine.

Dynamic Route File and ISR

Now that we have the Apollo Client configured, the next step is to set up how often we want Next.js to rebuild the page and get fresh data. This is set on an interval in time of seconds. This can be done using their ISR data fetching method.

I will add this timed interval in my dynamic route file which uses the slug as a parameter in the [slug].js file at the bottom in my getStaticProps function:

import { client } from "../lib/apollo";
import { gql } from "@apollo/client";
import Head from "next/head";

export default function SlugPage({ post }) {
  return (
    <div>
      <Head>
        <title>Headless WP Next Starter</title>
        <link rel="icon" href="favicon.ico"></link>
      </Head>

      <main>
        <div className="siteHeader">
          <h1 className="title">{post.title}</h1>
          <p>
            ✍️ &nbsp;&nbsp;
            {`${post.author.node.firstName} ${post.author.node.lastName}`} | 🗓️
            &nbsp;&nbsp;{new Date(post.date).toLocaleDateString()}
          </p>
        </div>
        <article dangerouslySetInnerHTML={{ __html: post.content }}></article>
      </main>
    </div>
  );
}

export async function getStaticProps({ params }) {
  const GET_POST = gql`
    query PostBySlug($id: ID!) {
      post(id: $id, idType: SLUG) {
        title
        content
        date
        author {
          node {
            firstName
            lastName
          }
        }
      }
    }
  `;
  //  the params argument for this function corresponds to the dynamic URL segments
  //  we included in our page-based route. So, in this case, the `params` object will have
  //  a property named `uri` that contains that route segment when a user hits the page
  const response = await client.query({
    query: GET_POST,
    variables: {
      id: params.slug,
    },
  });
  const post = response?.data?.post;

  return {
    props: {
      post,
    },
    revalidate: 5,
  };
}

Code language: JavaScript (javascript)

At the very bottom, you can see that I added the revalidate prop and set it to a 5-second interval. This will trigger a regeneration of this post detail page. Combined with WPGraphQL Smart Cache, the instant and freshly updated data will be received and rendered quickly and cached after that.

On your own project or if you cloned down my Next.js. starter, give it a try. Run the command npm run build in your terminal to run a production build of your site. Then run the command npm run start, pull up the browser, and go to a post detail page.

Then go back to WP Admin, edit the post you are on, and see how fast it revalidates and updates to the latest post. Then, once it’s cached, the request is instant as displayed here:

Speedy and Performant Invalidation and Response! 🚀

Conclusion…

The WPGraphQL Smart Cache plugin is a tool that supports and solves cache invalidation and caching optimally for WPGraphQL queries. The nuance and difficulty of cache invalidation within Headless WordPress have just gotten easier thanks to Jason Bahl and Mark Kelnar.

I touched on some high-level key features of the plugin, I encourage everyone to dive into the repo and readme as mentioned to get their hands dirty and explore all the other awesome features in this plugin.

There are more changes and updates to come. So as always stay tuned! We also would love to hear your feedback, thoughts, and projects you are doing in Headless WordPress so hit us up in our Discord!