Edgio
Edgio

GraphQL Caching

Edgio provides full support for caching GraphQL APIs. Putting Edgio in front of your GraphQL API can significantly improve its performance while reducing the amount of traffic that reaches your origin by serving cached queries from the network edge.

Example

The sections below walk you through configuring your Edgio project and creating the necessary routing rules to cache GraphQL responses.

Project Configuration

To deploy Edgio in front of your GraphQL API, install the Edgio CLI and create a new Edgio configuration:

Bash
1$ npm i -g @layer0/cli # yarn global add @layer0/cli
2$ 0 init

For more information on adding Edgio to an existing app, see Getting Started.

Configure the Origin

To configure the origin domain from which your GraphQL API is served, add a backend to layer0.config.js. For example:

JavaScript./layer0.config.js
1// layer0.config.js
2module.exports = {
3 backends: {
4 graphql: {
5 domainOrIp: 'graphql-origin.my-site.com', // the hostname for your origin graphql server(s)
6 hostHeader: 'graphql.my-site.com', // the hostname that clients use to connect to your graphql api
7 },
8 },
9}

Add Caching Rules

There are two ways to cache GraphQL responses using Edgio: by adding caching rules to your Edgio router or by using the cache-control header.

Using the Edgio Router

Imagine you have a query named GetProduct:

JavaScript
1export const GET_PRODUCT_QUERY = gql`
2 query GetProduct {
3 product(id: $productId) {
4 name
5 description
6 price
7 }
8 }
9`

You can add a caching rule for this query by using the graphqlOperation method, which is designed to comply with the operationName convention of the Apollo client ecosystem.

JavaScript./routes.js
1import { Router } from '@layer0/core'
2
3export default new Router().graphqlOperation('GetProduct', ({ cache, proxy }) => {
4 cache({
5 edge: {
6 maxAgeSeconds: 60 * 60, // cache responses for one hour
7 staleWhileRevalidateSeconds: 60 * 60 * 24, // serve stale responses for up to 24 hours
8 },
9 })
10 proxy('graphql') // forward requests to the GraphQL API origin we defined in layer0.config.js
11})

Match Operations by Regular Expression

The graphqlOperation method also allows you to match operations using a regular expression:

JavaScript
1export default new Router().graphqlOperation(/product/i, ({ cache, proxy }) => {
2 /* ... */
3})

Alter the Default GraphQL API Path

Most GraphQL APIs are hosted on the /graphql path. The graphqlOperation method will only match requests sent to /graphql by default. To use a different path, specify the path option:

JavaScript
1export default new Router().graphqlOperation(
2 {
3 path: '/gql-api' /* override the default /graphql path */,
4 name: 'GetProduct' /* name can also be a regular expression */,
5 },
6 ({ cache, proxy }) => {
7 /* ... */
8 },
9)

Use the Cache-Control Header

Edgio supports caching GraphQL responses at the network edge using the standard cache-control HTTP response header. For example, to cache the results of a query for one hour, add the following header to your response:

1cache-control: max-age=3600

You can also serve stale responses while fetching a fresh response from the origin by using stale-while-revalidate. For example, to allow stale responses to be served for up to 24 hours, use:

1cache-control: max-age=3600, stale-while-revalidate=86400

Cache Key

Regardless of the method you choose to define caching rules, Edgio incorporates the request body into the cache key for all POST requests. This means that if two requests have different request bodies, their responses will be cached separately.

Invalidate Stale Queries

Edgio gives you the ability to purge individual queries from the edge cache by assigning surrogate keys to each cached response.

Assign Surrogate Keys

To invalidate a cached query, you must first assign a surrogate key to the response before it is cached. You can do this using the router:

Use deriveSurrogateKeysFromJson

JavaScript./routes.js
1import { Router, deriveSurrogateKeysFromJson } from '@layer0/core'
2
3export default new Router().graphqlOperation('GetProduct', ({ cache, proxy }) => {
4 cache({
5 edge: {
6 maxAgeSeconds: 60 * 60, // cache responses for one hour
7 staleWhileRevalidateSeconds: 60 * 60 * 24, // serve stale responses for up to 24 hours
8 },
9 })
10 proxy('graphql', {
11 // Assigns a surrogate key to each response
12 transformResponse: deriveSurrogateKeysFromJson(json => [`product.${json.id}`]),
13 })
14})

Use the x-0-surrogate-key Response Header

You can also assign surrogate keys by adding an x-0-surrogate-key header to the response from the origin. Separate multiple keys with spaces:

1x-0-surrogate-key: key1 key2 key3

Handle Conflicts

If the origin returns an x-0-surrogate-key response header and deriveSurrogateKeysFromJson is also used for a given request, you can specify whether the surrogate keys should be merged, or the ones from the router should override those in the origin response:

To merge surrogate keys:

JavaScript
1deriveSurrogateKeysFromJson(json => [`product.${json.id}`], { onConflict: 'merge' })

To ignore the surrogate keys from the origin:

JavaScript
1deriveSurrogateKeysFromJson(json => [`product.${json.id}`], { onConflict: 'override' })

Purge by Surrogate Key

To purge all responses with a given surrogate key, use the Edgio CLI’s cache-clear command.

Bash
1layer0 cache-clear --team=my-team --site=my-site --environment=production --surrogate-key="product.1"

For more information, see clearing the cache from the CLI.

You can also purge responses by surrogate key via the REST API by specifying the surrogateKeys option.