Apollo boost - __typename в запросе предотвращает новую мутацию
У меня есть проблема в моем проекте метеор / реагировать / Аполлон (с наддувом). Когда я запрашиваю данные с сервера, он добавляет __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 ко всем моим схемам...
но ни один из них, похоже, не подходит для "простоты", которую, как предполагается, приносит Аполлон для запросов. Я надеюсь, что есть более простое, более логичное решение, но пока не смог найти ни одного.
1 ответ
Даже если использовать apollo-client
и не apollo-boost
Вы не должны устанавливать addTypename
ложно, если у вас нет веских причин для этого. __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
}
}
Вы не должны удалять __typename. Они предназначены для кеша, а также необходимы для типов объединения. Наверное стоит дождаться обновления от apollo. К сожалению, у меня тоже возникла проблема, и я не смог найти подходящего решения. Сначала я просто удалял все имена типов, но теперь у меня проблема с типами объединения.
Отсюда"__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
})
}