Повышение Apollo - __typename в запросе предотвращает новую мутацию

У меня проблема в моем проекте meteor / response / apollo (с ускорением). Когда я запрашиваю данные с сервера, он добавляет __typename к каждому объекту и подобъекту в моем запросе, но в моем случае это создает серьезную проблему, поскольку я обычно повторно использую эти данные для отправки их в другую мутацию. Теперь другая мутация сообщает мне об ошибке, потому что поле __typename не определено в моей схеме graphql.

Я попытался исправить это, добавив поле addTypename: false к моему клиенту apollo, но это ничего не изменило (обратите внимание, я использую apollo boost, возможно, поэтому он не работает):

const client = new ApolloClient({
    uri: Meteor.absoluteUrl('graphql'),
    addTypename: false,
    request: operation =>
        operation.setContext(() => ({
            headers: {
                authorization: Accounts._storedLoginToken()
            }
        }))
})

Также кажется, что даже если бы он работал, он не очень оптимизирован. Мне кажется очень проблематичным, что в результаты запроса добавляется поле, и я удивлен, что не нашел в Интернете четкого решения. Некоторое предлагаемое решение, где:

  • фильтровать вручную на стороне клиента
  • добавить промежуточное ПО в apollo
  • добавить поле __typename во все мои схемы ...

но ни один из них, похоже, не соответствует той «простоте», которую, как предполагается, предлагает Аполлон для запросов. Надеюсь, есть более простое и логичное решение, но пока не нашел.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
2
0
3 523
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Даже если вы используете apollo-client, а не apollo-boost, вы не должны устанавливать для addTypename значение false, если у вас нет веских причин для этого. Поле __typename используется InMemoryCache для нормализации результатов запроса, поэтому его пропуск может привести к неожиданному поведению при кэшировании.

К сожалению, в этой проблеме нет «серебряной пули». Запрос запроса и последующее использование данных этого запроса в качестве переменной для другого запроса может быть истолковано как неправильное использование API. Type, возвращаемый запросом, и Input Type, используемый в качестве аргумента, - это совершенно разные вещи, даже если в качестве объектов Javascript они совместно используют одно или несколько полей. Точно так же, как вы не можете взаимозаменяемо использовать типы и типы ввода в схеме, не следует ожидать, что они могут использоваться взаимозаменяемо на стороне клиента.

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

Если вы используете какой-либо запрос для заполнения одного или нескольких входов, а затем используете значение этих входов внутри мутации, то вы, вероятно, уже переводите исходные данные запроса в состояние компонента, а затем используете это в своей мутации. В этом сценарии __typename или любые другие нередактируемые поля, вероятно, не должны быть включены как часть состояния компонента в первую очередь.

В конце концов, мы надеемся, что подобные манипуляции будут исключением, а не правилом. Я бы создал некую вспомогательную функцию, чтобы «дезинфицировать» ваш ввод и двигаться дальше.

function stripTypenames (value) {
    if (Array.isArray(value)) {
        return value.map(stripTypenames)
    } else if (value !== null && typeof(value) === "object") {
      const newObject = {}
      for (const property in value) {
          if (property !== '__typename') {
            newObject[property] = stripTypenames(value[property])
          }
      }
      return newObject
    } else {
      return value
    }
}

Дэниел, еще раз спасибо за быстрый и четкий ответ. Я действительно повторно использую данные в состоянии компонента, изменяя их, если необходимо, а затем отправляю их обратно, поэтому я должен фильтровать их, как вы упомянули, поэтому я думаю, что решение - правильное решение. Однако я действительно сомневаюсь в graphQL / Apollo в том, как решается эта проблема. Для API, который должен идти прямо к делу и предоставлять только запрошенные данные, добавление поля к каждому отдельному объекту и подобъекту кажется излишним и противоречит сути. И многие запросы о выпуске github, похоже, повторяют это мнение.

Ivo 18.10.2018 15:01

Причина, по которой добавлен __typename, состоит в том, чтобы включить нормализацию кеша. Ознакомьтесь с разделом нормализации в (docs) [apollographql.com/docs/react/advanced/…. Если все ваши запросы были network-only или вы хотели реализовать свою собственную функцию dataIdFromObject, то вы могли бы обойтись установкой addTypename в false.

Daniel Rearden 18.10.2018 15:11

Я не говорю, что это правильно или неправильно, но Apollo делает определенные предположения о том, как будет использоваться API на основе соглашения. Это отражается в том, как компоненты Query и Mutation функционируют по-разному - хотя и запрос, и мутация могут делать одно и то же, существует предположение, что запросы будут извлекать данные, а мутации будут изменять данные. Точно так же, я считаю, есть предположение, что данные запроса не будут использоваться в качестве входных для другого запроса, поскольку это было бы нетрадиционным, даже если это технически возможно в некоторых случаях.

Daniel Rearden 18.10.2018 15:14

Если кому-то интересно, как я это решил: я использовал функцию пропуска из lodash для каждого объекта (и подобъекта), чтобы удалить ключ __typename сразу после того, как я запрашиваю свои данные из apollo и перед установкой их в состояние реакции. поэтому я могу изменить их и снова отправить состояние реакции в Мутацию, чтобы при необходимости сохранить новые данные.

Ivo 29.10.2018 12:58

Из здесь. '__typename' можно удалить с помощью следующей вспомогательной функции

const cleanedObject = omitDeep(myObject, "__typename")

const omitDeep = (obj, key) => {
    const keys = Object.keys(obj);
    const newObj = {};
    keys.forEach((i) => {
      if (i !== key) {
        const val = obj[i];
        if (val instanceof Date) newObj[i] = val;
        else if (Array.isArray(val)) newObj[i] = omitDeepArrayWalk(val, key);
        else if (typeof val === 'object' && val !== null) newObj[i] = omitDeep(val, key);
        else newObj[i] = val;
      }
    });
    return newObj;
  };

const omitDeepArrayWalk = (arr, key) => {
  return arr.map((val) => {
    if (Array.isArray(val)) return omitDeepArrayWalk(val, key)
    else if (typeof val === 'object') return omitDeep(val, key)
    return val
  })
}

Как использовать этот код с клиентом apollo и должны ли мы включить поле с именем addTypeName как истинное

Rigin Oommen 22.03.2019 06:49

Вы не должны удалять __typename. Они предназначены для кеша, а также необходимы для типов объединения. Наверное стоит дождаться обновления от apollo. К сожалению, у меня тоже возникла проблема, и я не смог найти подходящего решения. Сначала я просто удалял все имена типов, но теперь у меня проблема с типами объединения.

Другие вопросы по теме