问题
I have a headless Craft CMS that is returning data to my Nuxtjs app through a GraphQL endpoint through Apollo. I have a field that can return one of three different block types: richText
, image
, and pullQuote
.
My GraphQL endpoint looks like this:
query($section:[String], $slug:[String]) {
entries(section: $section, slug: $slug) {
id,
title,
uri,
... on blog_blog_Entry{
contentEngine{
__typename,
...on contentEngine_richText_BlockType{
__typename,
id,
richText
fontColor,
backgroundColor
}
...on contentEngine_image_BlockType{
__typename,
id,
backgroundColor,
imageWidth,
image {
id,
url
}
}
...on contentEngine_pullQuote_BlockType{
__typename,
id,
backgroundColor,
fontColor,
quote
}
}
}
}
}
It returns data just fine, but I'm getting this error when trying to use it within my Nuxt component:
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
The infuriating thing is that this documentation leads to a 404. I've found a few other GitHub tickets that reference this link, so I'm not sure what steps I should be following.
I think what I need to do is to teach Apollo's memory cache. Since my response isn't that complicated, I think I can get away with Defining PossibleTypes manually.
I've tried the following, but I don't think I'm understanding how to set this up properly:
const cache = new InMemoryCache({
possibleTypes: {
contentEngine: [
"contentEngine_richText_BlockType",
"contentEngine_pullQuote_BlockType",
"contentEngine_image_BlockType"
],
},
});
Any help for getting around this issue would be a huge help.
WARNING: heuristic fragment matching going on!
回答1:
As the documentation states, using possibleTypes
is only possible if using apollo-client
version 3.0 or higher, which is currently in beta. Unless you're using the @apollo/client
package as shown here, passing in the possibleTypes
parameter will do nothing.
Additionally, you need to make sure each property in the object you pass in is the name of a union or interface, not the name of a field. From the docs
You can pass a possibleTypes option to the InMemoryCache constructor to specify supertype-subtype relationships in your schema. This object maps the name of an interface or union type (the supertype) to the types that implement or belong to it (the subtypes).
In other words, instead of using contentEngine
as the key, you would use whatever the name of type of the contentEngine
field was.
If you're using an earlier version of apollo-client
, you'll need to create an IntrospectionFragmentMatcher
as outlined in the docs here.
回答2:
Anyone coming here because they're using Craft CMS headless the answer above is correct but to save you some reading basically you have to let Apollo of the schema.
import possibleTypes from './possibleTypes.json';
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: possibleTypes
})
Where you define your client add the following
cache: new InMemoryCache({
fragmentMatcher
})
To generate your schema you can either do the query below once and then paste the results into possibleTypes.json
(wouldn't recommend as you'll be doing it a lot) OR alternatively add that process to your nuxtInitServer
function to keep it updated automatically.
query {
__schema {
types {
name
kind
possibleTypes {
name
description
}
}
}
}
回答3:
I struggled with this myself, but after @mylesthe.dev (who responded above) spoke to me directly to provide fantastic support and some examples, I figured it out. So for anyone else still struggling like I was, here's the code (thanks to his work) which finally got things working for me:
First of all, in your nuxt.config.js set up your apollo configs:
// Apollo config and endpoint for graph ql
apollo: {
includeNodeModules: true,
clientConfigs: {
default: '@/apollo/client-configs/default.js' // This is where you'll set up the client and import the possible fragment types
}
},
Now we create the apollo client set up with the fragment schema file (which we'll create) in apollo/client-configs/default.js
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
import schema from './schema.json';
const fragmentMatcher = new IntrospectionFragmentMatcher({
introspectionQueryResultData: schema
})
export default ({req, app}) => {
const token = process.env.GRAPHQL_TOKEN
return {
httpEndpoint: process.env.API_ENDPOINT,
getAuth: () => `Bearer ${token}`, // remove if you're using the public schema
cache: new InMemoryCache({ fragmentMatcher }),
}
}
Now save an empty schema.json
file in apollo/client-configs/
.
Next we need to set up the script to query and generate this schema on nuxtServerInit
. You'll need fs
to write your schema file. You can install it with NPM: npm install --save fs
.
Once installed, go back to your nuxt.config and add fs to the build:
build: {
extend (config, ctx) {
config.node = {
fs: 'empty'
}
}
}
Then in your store/index.js
:
import Vuex from 'vuex';
import fetch from 'node-fetch';
import fs from 'fs';
const createStore = () => {
return new Vuex.Store({
actions: {
async nuxtServerInit({commit}, {app}) {
// only update fragements locally
if (process.env.NODE_ENV == 'local') {
// LOAD FRAGMENT TYPES AND STORE IN FILE
// APOLLO READS THIS FILE LATER
fetch(process.env.API_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json', authorization: 'Bearer ' + process.env.GRAPHQL_TOKEN, },
body: JSON.stringify({
variables: {},
query: `
{
__schema {
types {
kind
name
possibleTypes {
name
}
}
}
}
`,
}),
})
.then(result => result.json())
.then(result => {
// here we're filtering out any type information unrelated to unions or interfaces
const filteredData = result.data.__schema.types.filter(
type => type.possibleTypes !== null,
);
result.data.__schema.types = filteredData;
fs.writeFile('./apollo/client-configs/schema.json', JSON.stringify(result.data), err => {
if (err) {
console.error('Error writing fragmentTypes file', err);
}
});
});
}
},
}
});
};
export default createStore
Your schema should now be generated locally to the schema file and that file will be stored in the apollo cache.
来源:https://stackoverflow.com/questions/59690194/apollographql-heuristic-fragment-manual-matching