Layer0 provides full support for caching GraphQL APIs. Putting Layer0 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 Layer0 project and creating the necessary routing rules to cache GraphQL responses.
Project Configuration
To deploy Layer0 in front of your GraphQL API, install the Layer0 CLI and create a new Layer0 configuration:
$ npm i -g @layer0/cli # yarn global add @layer0/cli
$ 0 init
For more information on adding Layer0 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:
// layer0.config.js
module.exports = {
backends: {
graphql: {
domainOrIp: 'graphql-origin.my-site.com', // the hostname for your origin graphql server(s)
hostHeader: 'graphql.my-site.com', // the hostname that clients use to connect to your graphql api
},
},
}
Add Caching Rules
There are two ways to cache GraphQL responses using Layer0: by adding caching rules to your Layer0 router or by using the cache-control
header.
Using the Layer0 Router
Imagine you have a query named GetProduct
:
export const GET_PRODUCT_QUERY = gql`
query GetProduct {
product(id: $productId) {
name
description
price
}
}
`
You can add a caching rule for this query by using the graphqlOperation
method:
import { Router } from '@layer0/core'
export default new Router().graphqlOperation('GetProduct', ({ cache, proxy }) => {
cache({
edge: {
maxAgeSeconds: 60 * 60, // cache responses for one hour
staleWhileRevalidateSeconds: 60 * 60 * 24, // serve stale responses for up to 24 hours
},
})
proxy('graphql') // forward requests to the GraphQL API origin we defined in layer0.config.js
})
Match Operations by Regular Expression
The graphqlOperation
method also allows you to match operations using a regular expression:
export default new Router().graphqlOperation(/product/i, ({ cache, proxy }) => {
/* ... */
})
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:
export default new Router().graphqlOperation(
{
path: '/gql-api' /* override the default /graphql path */,
name: 'GetProduct' /* name can also be a regular expression */,
},
({ cache, proxy }) => {
/* ... */
},
)
Use the Cache-Control Header
Layer0 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:
cache-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:
cache-control: max-age=3600, stale-while-revalidate=86400
Cache Key
Regardless of the method you choose to define caching rules, Layer0 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
Layer0 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
import { Router, deriveSurrogateKeysFromJson } from '@layer0/core'
export default new Router().graphqlOperation('GetProduct', ({ cache, proxy }) => {
cache({
edge: {
maxAgeSeconds: 60 * 60, // cache responses for one hour
staleWhileRevalidateSeconds: 60 * 60 * 24, // serve stale responses for up to 24 hours
},
})
proxy('graphql', {
// Assigns a surrogate key to each response
transformResponse: deriveSurrogateKeysFromJson(json => [`product.${json.id}`]),
})
})
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:
x-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:
deriveSurrogateKeysFromJson(json => [`product.${json.id}`], { onConflict: 'merge' })
To ignore the surrogate keys from the origin:
deriveSurrogateKeysFromJson(json => [`product.${json.id}`], { onConflict: 'override' })
Purge by Surrogate Key
To purge all responses with a given surrogate key, use the Layer0 CLI’s cache-clear command.
layer0 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.