Apollo Boost-查询中的__typename防止新突变

时间:2018-10-18 12:12:18

标签: reactjs graphql apollo apollo-client apollo-boost

我在流星/反应/阿波罗(带升压)项目中遇到问题。当我从服务器查询数据时,它将__typename添加到查询中的每个对象和子对象,但就我的情况而言,这会造成一个主要问题,因为我通常会重复使用这些数据将其发送给其他突变。现在,另一个突变告诉我有一个错误,因为在我的graphql模式中未定义__typename字段。

我试图通过将addTypename:false字段添加到我的apollo客户端来进行修复,但是它没有任何改变(请注意,我使用的是apollo boost,这可能就是为什么它不起作用的原因):

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

看来,即使它工作起来也不是很优化。在我看来,将一个字段添加到查询结果中非常有问题,我很惊讶没有在网上找到任何明确的解决方案。一些建议的解决方案,其中:

  • 在客户端手动过滤
  • 将中间件添加到阿波罗
  • 将__typename字段添加到我的所有架构中...

但是它们似乎都不适合“简单”的阿波罗,它被认为可以带来查询。我希望提供一个更简单,更合乎逻辑的解决方案,但到目前为止,找不到任何解决方案。

3 个答案:

答案 0 :(得分:3)

即使使用apollo-client而不是apollo-boost,也不应将addTypename设置为false,除非您有充分的理由这样做。 __typename使用InMemoryCache字段对查询结果进行规范化,因此省略该字段可能会导致缓存方面的意外行为。

不幸的是,这个问题没有“灵丹妙药”。请求一个查询,然后将该查询的数据用作其他查询的变量,可以解释为滥用API。查询返回的Type和用作参数的Input Type是完全不同的东西,即使它们作为JavaScript对象共享一个或多个字段。就像您不能在模式中互换使用类型和输入类型一样,不应期望它们可以在客户端互换使用。

这也意味着,如果您发现自己处于这种情况下,则可能需要重新看一下架构设计。毕竟,如果数据已经存在于服务器上,则应该为它传递一个ID并在服务器端检索它就足够了,而不必传递整个对象。

如果您正在使用某个查询来填充一个或多个输入,然后使用一个突变内的这些输入的值,那么您可能已经将初始查询数据转换为组件状态,然后将其用于突变中。在这种情况下,一开始__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
    }
}

答案 1 :(得分:0)

来自 here。可以使用以下帮助程序功能删除“ __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
  })
}

答案 2 :(得分:0)

您不应删除__typename。它们用于高速缓存,还用于联合类型。可能应该等待阿波罗的更新。 不幸的是,我现在也遇到问题,找不到合适的解决方案。首先,我以前只是删除所有类型名称,但是现在我遇到了联合类型的问题。