从GraphQL响应中清除不需要的字段

ilr*_*ein 10 javascript ecmascript-6 graphql

我的GraphQL客户端请求一个对象。

这是一个相当简单的对象:

type Element {
    content: [ElementContent]
    elementId: String
    name: String
    notes: String
    type: String
    createdAt: String
    updatedAt: String
  }
Run Code Online (Sandbox Code Playgroud)

使用特殊类型ElementContent,它很小,看起来像这样:

  type ElementContent {
    content: String
    locale: String
  }
Run Code Online (Sandbox Code Playgroud)

现在,当我在客户端上查询此对象时,顶层对象和底层对象均具有其他属性(如果我尝试按原样克隆主体,则会干扰更新对象);

值得注意的是,GraphQL似乎__typename在父对象中提供了一个属性,而在子对象中,它们也具有typename和一个Symbol(id)属性。

在此处输入图片说明

我很乐意将此对象复制到状态,在状态下更新,然后克隆状态并将其发送给我的update突变。但是,由于GraphQL本身提供的未知属性,我遇到了麻烦。

我试着做:

delete element.__typename 效果很好,但随后我还需要遍历子级对象(动态对象数组),并且可能还必须删除这些属性。

我不确定在此等式中是否缺少某些内容,或者我应该只是在代码中苦苦挣扎,然后进行循环+删除(最初尝试进行forEach循环时收到错误)。我尝试做的事情有更好的策略吗?还是我走在正确的道路上,只需要一些良好的循环代码即可清除不需要的属性?

Rig*_*men 24

有三种方法可以做到这一点

第一种方式

像这样更新客户端参数,它将忽略graphql中不需要的字段。

apollo.create({
  link: http,
  cache: new InMemoryCache({
    addTypename: false
  })
});
Run Code Online (Sandbox Code Playgroud)

第二路

通过使用深省略包并将其用作中间件

const cleanTypeName = new ApolloLink((operation, forward) => {
  if (operation.variables) {

    operation.variables = omitDeep(operation.variables,'__typename')
  }
  return forward(operation).map((data) => {
    return data;
  });
});
Run Code Online (Sandbox Code Playgroud)

第三路

创建一个自定义的中间件并注入阿波罗

const cleanTypeName = new ApolloLink((operation, forward) => {
  if (operation.variables) {
    const omitTypename = (key, value) => (key === '__typename' ? undefined : value);
    operation.variables = JSON.parse(JSON.stringify(operation.variables), omitTypename);
  }
  return forward(operation).map((data) => {
    return data;
  });
});
Run Code Online (Sandbox Code Playgroud)

并注入中间件

const httpLinkWithErrorHandling = ApolloLink.from([
  cleanTypeName,
  retry,
  error,
  http,
]);
Run Code Online (Sandbox Code Playgroud)

首选方法是“ 第三种方法”,因为它没有任何第三种依赖关系,也没有缓存性能问题

  • 不幸的是,这个答案并不适用于许多现实生活中的案例。首先,问题是关于 GQL *响应*,选项 2 和 3 仅修改操作变量(发送到服务器),而不是响应。只有选项 1 可以覆盖两者(可能),但是还有另一个问题:当模式深度嵌套和/或使用片段时,每个选项都会破坏依赖于“__typename”的缓存。综上所述,这里没有很好的包罗万象的解决方案。有些选项可能适合您的情况,但如果您使用片段和/或缓存,那么您肯定只需要使用“__typename”即可。 (7认同)
  • 抱歉造成混淆,我问你为什么使用将“data”映射到自身的“.map”,如“.map((data) => { return data })”-我几乎在每个示例中都看到了它,但我不明白。它不会以任何方式操纵任何东西。 (5认同)
  • 为什么使用关联图“data => data”? (2认同)

Ali*_*iri 5

如果您想清除__typenameGraphQL 响应(从根及其子级),您可以使用graphql-anywhere包。

就像是: const wipedData = filter(inputFragment, rcvData);

  • inputFragment是一个定义字段的片段(您可以在此处查看详细信息)
  • rcvData是从 GraphQL 查询接收到的数据

通过使用该filter函数,wipedData仅包含您需要作为突变输入传递的必填字段。