Cache queries

Improve network performance by caching GraphQL queries.

To improve network performance for large query strings, the GraphQL filter supports automatic persisted queries. A persisted query consists of the query string and the query's SHA-256 hash that are cached on the GraphQL server side. When you enable query caching, a client can then send the query hash instead of the full query string, which reduces request sizes. Persisted queries are especially effective when clients send queries as GET requests, because clients can take advantage of the browser cache and integrate with a CDN.

Depending on your client and edge caching architecture, the query caching performance benefits can also apply to responses. Although this policy does not cache responses, persisting queries with a query hash allows clients to cache the response in a client-local cache. Query caching also allows the CDN layer to cache the response. Note that responses are unaffected by query caching.

You can also prevent malicious requests to your GraphQL servers by specifying a list of allowed query hashes in a GraphQLAllowedQueryPolicy.

Before you begin

This guide assumes that you use the same names for components like clusters, workspaces, and namespaces as in the getting started, and that your Kubernetes context is set to the cluster you store your Gloo config in (typically the management cluster). If you have different names, make sure to update the sample configuration files in this guide.
  1. Set up Gloo Gateway in a single cluster.
  2. Deploy sample apps.
  3. Configure an HTTP listener on your gateway. The RouteTable in this guide is not required, because you create a GraphQL-specific route table instead.
  4. Follow the Get started with GraphQL in Gloo Gateway guide to define example GraphQL schema and resolvers and configure routing.

Configure GraphQL query caching

You can apply a GraphQLPersistedQueryCachePolicy policy at the route level. For more information, see Applying policies.

Review the following sample configuration files.

apiVersion: resilience.policy.gloo.solo.io/v2
kind: GraphQLPersistedQueryCachePolicy
metadata:
  name: bookinfo-query-cache
  namespace: bookinfo
spec:
  applyToRoutes:
  - route:
      labels:
        route: graphql-bookinfo
  config:
    cacheSize: 1000

Review the following table to understand this configuration. For more information, see the API docs.

Setting Description
spec.applyToRoutes Use labels to configure which GraphQL routes to apply the policy to. This example label matches the app and route from the example route table that you previously applied in the GraphQL getting started guide. If omitted or empty, the policy applies to no routes in the workspace. If more than one GraphQLPersistedQueryCachePolicy applies to a GraphQL route, the oldest policy is applied.
cacheSize The number of queries to store in the persisted query cache. Defaults to 1000.

Specify cache control directives

By default, the GraphQL server adds the Cache-Control header to each response that it returns, which describes the response's cache policy. The cache control policy signals to CDNs to cache the HTTP GET responses, and also describes how the response should be cached.

In the GraphQL schema that you define in your ApiDoc Gloo CR, you might add the @cacheControl directive for the folllowing arguments:

In the following example, the @cacheControl(maxAge: 60) directive for the top-level query type ensures that responses to queries are fresh in the cache for a maximum of 60 seconds. Additionally, the @cacheControl(maxAge: 30) directive for the fullName field indicates that this value is cached for a maximum of only 30 seconds, instead of 60 seconds. Field-specific directives override type-level directives.

apiVersion: apimanagement.gloo.solo.io/v2
kind: ApiDoc
metadata:
  name: bookinfo-rest-apidoc
  namespace: bookinfo
spec:
  graphql:
    schemaDefinition: |-
      type Query @cacheControl(maxAge: 60) {
        GetAllAccounts: [Account]
        GetAccount(account_id: Int): Account
      }
      type Mutation {
        CreateAccount(account: Account): Account
      }
      type Account {
        fullName: 		String @cacheControl(maxAge: 30)
        email: 			  String
        phoneNumber: 	String
        address: 		  String
      }
      ...