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

Ivo*_*Ivo 2 apollo reactjs graphql apollo-client apollo-boost

我的流星/反应/阿波罗(带提升)项目有问题。当我从服务器查询数据时,它会将 __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()
            }
        }))
})
Run Code Online (Sandbox Code Playgroud)

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

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

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

Dan*_*den 5

即使使用apollo-clientand not 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
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 丹尼尔,再次感谢您快速明确的回答。我确实在组件状态下重用数据,在需要时修改它们,然后将它们发回,因此我必须按照您提到的方式过滤它们,所以我想解决方案是正确的解决方案。但是我真的很怀疑 graphQL/Apollo 如何处理这个问题。对于应该直截了当并仅提供请求的数据的 API,向每个单个对象和子对象添加一个字段似乎有点矫枉过正,而且不利于整点。很多 github 问题请求似乎重新加入了这个观点。 (3认同)