Introspection fragment matching


The Prismic GraphQL API uses Union types in a number of places. In order to accurately map these fields for those of you using Apollo, you will need to use the IntrospectionFragmentMatcher as explained in the Apollo GraphQL docs. Here we will discuss how to do this in your project.

Note that the examples in this article is inspired by Chandu's excellent article on this topic. You can read it here.

Schema query to retrieve the fragment types

The first step is to create a file that will query the GraphQL schema from the API and save the results in a JSON file. Below you can find what the file should look like.

Update the repo ID

In the example below you'll need to update the Prismic repo ID. For example, if your repository url is https://my-awesome-repo.prismic.io, then your repo ID is my-awesome-repo.

Copy
const fetch = require('node-fetch');
const fs = require('fs');

const repoId = 'your-repo-name'; // Update this with your repo id

fetch(`https://${repoId}.prismic.io/api`)
  .then((r) => r.json())
  .then((data) => {
    const ref = data.refs.find((r) => r.id === 'master');
    if (!ref) return;
    fetch(
      `https://${repoId}.prismic.io/graphql?query=%7B%20__schema%20%7B%20types%20%7B%20kind%20name%20possibleTypes%20%7B%20name%20%7D%20%7D%20%7D%20%7D`,
      {
        headers: {
          'prismic-ref': ref.ref,
        },
      },
    )
      .then((result) => result.json())
      .then((result) => {
        const filteredResults = result;
        const filteredData = result.data.__schema.types.filter(
          (type) => type.possibleTypes !== null,
        );
        filteredResults.data.__schema.types = filteredData;
        fs.writeFileSync('./src/utils/fragmentTypes.json', JSON.stringify(filteredResults.data), (err) => {
          if (err) {
            console.error('Error writing fragmentTypes file', err);
          } else {
            console.log('Fragment types successfully extracted!');
          }
        });
      });
  });

What this is doing is pretty straightforward. First, it is making an Introspection query to the GraphQL API. Here is the GraphQL query being made:

Copy
{
  __schema {
    types {
      kind
      name
      possibleTypes {
        name
      }
    }
  }
}

Then it takes the results and filters out any object with a null value for the possibleTypes field. After this, it takes the remaining types and stores them in a JSON file named /src/utils/fragmentTypes.json.

Pass the fragment types to the InMemoryCache

Next you'll need to use the fragment types when you instantiate the client object. Again you'll see that you'll need to update the following code snippet with your repo id.

Copy
import { PrismicLink } from 'apollo-link-prismic';
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import ApolloClient from 'apollo-client';
import fragmentTypes from './fragmentTypes.json'; // You may have to update this path

const apiEndpoint = 'https://your-repo-name.cdn.prismic.io/graphql'; // Update this with your repo id
const fragmentMatcher = new IntrospectionFragmentMatcher(
  { introspectionQueryResultData: fragmentTypes },
);

export const client = new ApolloClient({
  link: PrismicLink({ uri: apiEndpoint }),
  cache: new InMemoryCache({ fragmentMatcher }),
});

Build and save the fragment types

With all this in place, the final step is to run the first file that you created. When using Node, you can add the following script to build the fragment types file. Add this to the "scripts" section of your package.json:

Copy
"build-fragment": "node src/utils/schemaQuery.js"

Now when you run npm run build-fragment, the fragment types will be retrieved and stored in the /src/utils/fragmentTypes.json file.

To ensure that your fragment types are always up-to-date it's recommended that you run the build-fragment command when running your development server or creating your production build. Here's an example of how to modify the scripts in your package.json file:

Copy
"scripts": {
  "start": "npm run build-fragment && react-scripts start",
  "build": "npm run build-fragment && react-scripts build",
  "build-fragment": "node src/utils/schemaQuery.js"
},