Apollo+GraphQL - 启发式片段手动匹配

Apollo+GraphQL - Heuristic Fragment Manual Matching

我有一个无头 Craft CMS,它通过 Apollo 通过 GraphQL 端点 return 将数据发送到我的 Nuxtjs 应用程序。我有一个字段可以 return 三种不同块类型之一:richTextimagepullQuote.

我的 GraphQL 端点如下所示:

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,但在我的 Nuxt 组件中尝试使用它时出现此错误:

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

令人气愤的是,此文档导致 404。我发现了一些 other GitHub tickets 引用了此 link,所以我不确定应该遵循哪些步骤。

我觉得我需要做的是教Apollo的内存缓存。由于我的回答没有那么复杂,我想我可以不用 Defining PossibleTypes manually.

我已经尝试了以下方法,但我认为我不了解如何正确设置它:

const cache = new InMemoryCache({
    possibleTypes: {
        contentEngine: [
            "contentEngine_richText_BlockType", 
            "contentEngine_pullQuote_BlockType", 
            "contentEngine_image_BlockType"
        ],
    },
});

解决此问题的任何帮助都是巨大的帮助。

WARNING: heuristic fragment matching going on!

如文档所述,只有使用 apollo-client 3.0 或更高版本(目前处于测试阶段)才能使用 possibleTypes。除非您使用 @apollo/client 包,如 here 所示,否则传入 possibleTypes 参数将不会执行任何操作。

此外,您需要确保您传入的对象中的每个 属性 都是联合或接口的名称, 而不是 字段的名称。来自 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).

换句话说,不是使用 contentEngine 作为键,而是使用 contentEngine 字段的类型名称。

如果您使用的是 apollo-client 的早期版本,则需要按照文档 here.

中的说明创建一个 IntrospectionFragmentMatcher

任何来这里的人都是因为他们正在使用 Craft CMS headless 上面的答案是正确的,但为了节省您的阅读时间,基本上您必须让 Apollo 了解架构。

import possibleTypes from './possibleTypes.json';
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
const fragmentMatcher = new IntrospectionFragmentMatcher({
    introspectionQueryResultData: possibleTypes
})

在您定义客户端的位置添加以下内容

cache: new InMemoryCache({
    fragmentMatcher
})

要生成您的架构,您可以执行下面的查询一次,然后将结果粘贴到 possibleTypes.json(不推荐,因为您会经常这样做)或者将该过程添加到您的nuxtInitServer 保持自动更新的功能。

query {
  __schema {
    types {
      name
      kind
      possibleTypes {
        name
        description
      }
    }
  }
}

我自己也曾为此苦苦挣扎,但在@mylesthe.dev(上面的回复)直接与我交谈以提供出色的支持和一些示例后,我明白了。因此,对于仍然像我一样挣扎的其他人,这里是代码(感谢他的工作)终于让事情对我有用:

首先,在您的 nuxt.config.js 中设置您的 apollo 配置:

// 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
  }
},

现在我们在 apollo/client-configs/default.js

中创建使用片段模式文件(我们将创建)设置的 apollo 客户端
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 }),
    }
}


现在在 apollo/client-configs/ 中保存一个空的 schema.json 文件。

接下来我们需要设置脚本以在 nuxtServerInit 上查询和生成此架构。您需要 fs 来编写架构文件。您可以使用 NPM 安装它:npm install --save fs.

安装后,返回您的 nuxt.config 并将 fs 添加到构建中:

build: {
  extend (config, ctx) {
    config.node = {
      fs: 'empty'
    }
  }
}

然后在你的 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

您的模式现在应该在本地生成到模式文件,该文件将存储在 apollo 缓存中。