GraphQL Fragments with Nuxt Apollo Plugin
Apollo module for NuxtJS makes GraphQL querying very approachable even to complete GraphQL beginners. However, any query involving a union type will fail. Resolving the issue will require you to learn more about the Apollo client internals.
Basic GraphQL setup
For reference, the initial setup of the Apollo GraphQL client in a NuxtJS application consists of the following steps:
Installing the Apollo module for NuxtJS and a helper library for embedding GraphQL queries in TypeScript code:
npm i @nuxtjs/apollo graphql-tag
Registering the module with NuxtJS and configuring the Apollo GraphQL client (both in the
nuxt.config.js
configuration file):export default { //... modules: ["@nuxtjs/apollo"], apollo: { clientConfigs: { default: { httpEndpoint: "http://localhost:3000/graphql", }, }, }, };
Writing the query in a TypeScript file of choice:
import gql from "graphql-tag"; export const BOOKS_QUERY = gql` query Books { books { ... on Ebook { id author title pages } ... on Audiobook { id author title minutes } } } `;
Generating the type definitions for the query using the Apollo Codegen tooling (with NPM scripts):
{ "scripts": { "apollo:download": "apollo client:download-schema graphql/schema.json --endpoint http://localhost:3000/graphql", "apollo:generate": "apollo client:codegen --outputFlat=graphql/types/ --target typescript --includes=graphql/queries/**.ts --localSchemaFile=graphql/schema.json --tagName=gql" } }
Executing the query (e.g. in a page or a component):
@Component({ async fetch(this: IndexPage) { const result = await this.$apollo.query<Books>({ query: BOOKS_QUERY }); this.books = result.data.books; }, }) export default class IndexPage extends Vue { books: Books_books[] = []; }
Following these steps will result in the following error:
ERROR You are using the simple (heuristic) fragment matcher, but your queries contain union or interface types. Apollo Client will not be able to accurately map fragments. To make this error go away, use the IntrospectionFragmentMatcher as described in the docs: https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher
Fragment matcher configuration
The error message links to the documentation for version 3.0 of the client. The NuxtJS Apollo module is still using version 2.6 which has slightly different configuration steps.
With any client version, the IntrospectionFragmentMatcher
will require introspection information. The file can be generated from the GraphQL schema using the GraphQLCodeGenerator tool and its Fragment Matcher plugin.
They first need to be installed:
npm i -D @graphql-codegen/cli @graphql-codegen/fragment-matcher
Then the configuration file must be prepared:
schema: ./graphql/schema.json
overwrite: true
generates:
./graphql/introspection.json:
plugins:
- fragment-matcher
And finally, the tool can be run from an NPM script:
{
"scripts": {
"apollo:introspection": "graphql-codegen"
}
}
The advanced Apollo client configuration required by the IntrospectionFragmentMatcher
can't be embedded in the nuxt.config.js
file. An external JavaScript file can be referenced instead:
export default {
//...
apollo: {
clientConfigs: {
default: "~/plugins/apollo-client-config.js",
},
},
};
This JavaScript file will contain the full Apollo client configuration (the IntrospectionFragmentMatcher
and the endpoint URL that was previously specified directly in the configuration file):
import {
IntrospectionFragmentMatcher,
InMemoryCache,
} from "apollo-cache-inmemory";
import introspectionQueryResultData from "../graphql/introspection.json";
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData,
});
export default function (_context) {
return {
httpEndpoint: "http://localhost:3000/graphql",
cache: new InMemoryCache({ fragmentMatcher }),
};
}
With this updated configuration, union types can now be queried without errors. Of course, if the GraphQL schema changes it will need to be downloaded again and the introspection.json
file might need to be regenerated. Nothing else will need to change.
A full sample, including a simple GraphQL server written in NestJS is available from my GitHub repository.
The default Apollo client configuration uses a simple heuristics-based fragment matcher that doesn't need any input from the schema but might therefore fail with more complex types and queries. This can be resolved by using a more advanced introspection-based heuristics matcher. An additional one-time configuration is required for it to work.