Apollo + GraphQL - эвристическое сопоставление фрагментов вручную

У меня есть Craft CMS без головы, которая возвращает данные в мое приложение Nuxtjs через конечную точку GraphQL через Apollo. У меня есть поле, которое может возвращать один из трех разных типов блоков: richText, image и pullQuote.

Моя конечная точка 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
                }
            }
        }
    }
}

Он отлично возвращает данные, но я получаю эту ошибку при попытке использовать его в своем компоненте Nuxt:

Вы используете простой (эвристический) сопоставитель фрагментов, но ваши запросы содержат типы объединения или интерфейса. Клиент Apollo не сможет точно отображать фрагменты. Чтобы устранить эту ошибку, используйте IntrospectionFragmentMatcher, как описано в документации: https://www.apollographql.com/docs/react/advanced/fragments.html#fragment-matcher

Раздражает то, что эта документация приводит к ошибке 404. Я нашел несколько другие билеты GitHub, которые ссылаются на эту ссылку, поэтому я не уверен, какие шаги мне следует предпринять.

Я думаю, что мне нужно научить кэш памяти Apollo. Поскольку мой ответ не такой уж сложный, я думаю, что смогу обойтись без Определение возможных типов вручную.

Я пробовал следующее, но не думаю, что понимаю, как это правильно настроить:

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

Любая помощь в решении этой проблемы будет огромным подспорьем.

ВНИМАНИЕ: происходит эвристическое сопоставление фрагментов!


person Rob Erskine    schedule 10.01.2020    source источник


Ответы (3)


Как указано в документации, использование possibleTypes возможно только при использовании apollo-client версии 3.0 или выше, которая в настоящее время находится в стадии бета-тестирования. Если вы не используете пакет @apollo/client, как показано здесь, передача параметра possibleTypes ничего не даст.

Кроме того, вам необходимо убедиться, что каждое свойство в переданном вами объекте является именем объединения или интерфейса, а не именем поля. Из документации

Вы можете передать параметр possibleTypes конструктору InMemoryCache, чтобы указать отношения супертип-подтип в вашей схеме. Этот объект сопоставляет имя интерфейса или типа объединения (супертип) с типами, которые реализуют его или принадлежат к нему (подтипы).

Другими словами, вместо использования contentEngine в качестве ключа вы должны использовать любое имя типа поля contentEngine.

Если вы используете более раннюю версию apollo-client, вам необходимо создать IntrospectionFragmentMatcher, как указано в документах здесь.

person Daniel Rearden    schedule 11.01.2020
comment
Спасибо, Даниэль. Ваш ответ привел меня к этой теме, которая помогла мне понять, как реализовать IntrospectionFragmentMatcher Apollo с Nuxtjs. - person Rob Erskine; 13.01.2020

Любой, кто приходит сюда, потому что он использует Craft CMS без головы, ответ выше правильный, но, чтобы сэкономить вам немного чтения, в основном вы должны позволить 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
      }
    }
  }
}
person mylesthe.dev    schedule 19.03.2020
comment
Привет @ mylesthe.dev, спасибо за публикацию - я пытаюсь перейти на график QL с помощью Nuxt, но я относительно новичок в обоих. Я столкнулся с этой проблемой для запросов к нескольким матричным полям. Есть ли шанс, что вы могли бы предоставить немного больше контекста относительно того, где я помещаю каждый из приведенных выше фрагментов в Nuxt, чтобы решить эту проблему глобально? - person ToddPadwick; 26.01.2021
comment
@ToddPadwick прислал вам несколько примеров :) - person mylesthe.dev; 05.02.2021

Я сам боролся с этим, но после того, как @ 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, настроенный с файлом схемы фрагмента (который мы создадим) в 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 }),
    }
}


Теперь сохраните пустой schema.json файл в apollo/client-configs/.

Затем нам нужно настроить сценарий для запроса и генерации этой схемы на 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.

person ToddPadwick    schedule 05.02.2021
comment
fs перемещен, как показано сюда, и, кроме того, вы не нужно устанавливать fs, потому что он поставляется прямо из коробки с Node (и, следовательно, с Nuxt). Кроме того, это не сработает, если вы перейдете в SPA режим только с Nuxt (почему, но все же), потому что вы будете yarn build, а не yarn generate, и это приведет к тому, что сервер Node не вызывается. nuxtjs.org/docs/2.x/concepts/nuxt-lifecycle / # server Спасибо за руководство. :) - person kissu; 09.04.2021