Caching with Apollo Server and the Client

Hopefully, when deploying your first application, you'll soon get a growing user base. You're required to improve the performance and efficiency of your application. One way this can be done is through standard improvements, such as code refactoring. Another crucial thing to do is caching. Not just files such as our CSS and JavaScript files should be cached, but also the requests that we send.

Apollo provides Automatic Persisted Queries (APQ), which is a technique that significantly reduces bandwidth usage and carries out caching through unique IDs per request. The workflow of this technique is as follows:

  1. The client sends a hash instead of the full query string.
  2. Apollo Server tries to find this hash inside its cache.
  3. If the server finds the corresponding query string to the hash, it'll execute it and respond with its result.
  4. If the server doesn't find the hash inside its cache, it'll ask the client to send the hash along with the actual query string. The back end will then save this hash with the query string for all future requests and respond to the client's request.

There are two server-side changes that we have to do. One is in the initialization of Apollo Server. Extend the graphql index.js by adding the following two parameters to the ApolloServer options:

cacheControl: {
defaultMaxAge: 5,
stripFormattedExtensions: false,
calculateCacheControlHeaders: true,
},

The cacheControl object sets cacheControl properties for all our requests. The standard time inserted in this case is 5 seconds. Using cache control, you can also store public GraphQL requests inside a CDN to improve performance.

Setting up a CDN for your application is a vast topic that wouldn't be possible to cover in just one chapter. It requires a significant amount of work. If you want to use Apollo together with a CDN, read up on this in the official documentation: https://www.apollographql.com/docs/apollo-server/v2/whats-new.html#CDN-integration.

The second change is to enable cache control in the GraphQL schema. Just copy the following code into the schema.js file:

enum CacheControlScope {
PUBLIC
PRIVATE
}

directive @cacheControl (
maxAge: Int
scope: CacheControlScope
) on FIELD_DEFINITION | OBJECT | INTERFACE

We have to add the preceding lines of code because there seems to be a problem with the makeExecutableSchema function, which removes the @cacheControl directive. By adding it in our schema, we add our custom directive, which we can use.

If you now execute any query, the response will include an extensions object that looks like the following example:

In this case, the maxAge field has been applied to each layer of our GraphQL request. As you can see, the users in the third layer and the avatar images all have different maximum ages when compared to the posts. You can define the maxAge per type and field specifically.

If you open your schema.js file, you can change your User type to reflect the preceding screenshot, as follows:

type User @cacheControl(maxAge: 120) {
id: Int
avatar: String @cacheControl(maxAge: 240)
username: String
email: String
}

The @cacheControl directive takes care of all of this internally in Apollo Server.

To persist our queries, we have to change some aspects of our SSR code. Before we do this, however, we need to install a package using npm:

npm install --save apollo-link-persisted-queries

This package provides a special Apollo Client link to use persisted queries. Import it at the top of both the apollo.js file in the ssr folder and the index.js in the apollo folder of the client:

import { createPersistedQueryLink } from 'apollo-link-persisted-queries';

We'll now create a new link with the createPersistedQueryLink function and then connect it with our existing HttpLink, which is initialized by the createUploadLink function. The following snippet shows how this can be implemented for the client-side code:

const httpLink = createPersistedQueryLink().concat(createUploadLink({
uri: location.protocol + '//' + location.hostname + port +
'/graphql',
credentials: 'same-origin',
}));

We execute the createPersistedQueryLink function and then use the concat function for our UploadLink. The result is then normally inserted into the split function, which is used to decide between the WebSocket link and UploadLink.

The SSR-related code looks pretty similar, but the function is directly executed within the Apollo.from function instead. In the apollo.js file from the apollo folder, replace the initialization of HttpLink with the following code:

createPersistedQueryLink().concat(new HttpLink({
uri: 'http://localhost:8000/graphql',
credentials: 'same-origin',
fetch
}));

As you know, we don't have UploadLink on the server side, so we're using the normal HttpLink instead. A GraphQL request will now include a hash instead of the regular query string on the first try. You can see an example in the following screenshot:

The variables are of course included, because they can change dynamically, but the query will always be the same. The server will try to find the hash or let the client resend the complete query string. This solution will save you and your users a significant amount of bandwidth and, as a result, speed up API requests.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.175.180