【问题标题】:Nested resolvers with depth greater than 1深度大于 1 的嵌套解析器
【发布时间】:2019-11-13 01:20:17
【问题描述】:

问题

看看这个 GraphQL 查询,

query {
    asset {
        name
        interfaces {
            created 
            ip_addresses {
                value
                network {
                    name
                }
            }
        }
    }
}

我如何只为 ip_addresses 上的 network 字段定义解析器?

我的第一个想法

阅读docs 给出单个嵌套查询的示例,例如

const resolverMap = {
  Query: {
    author(obj, args, context, info) {
      return find(authors, { id: args.id });
    },
  },
  Author: {
    posts(author) {
      return filter(posts, { authorId: author.id });
    },
  },
};

所以我想 - 为什么不将此模式应用于嵌套属性?

const resolverMap = {  
  Query: {
      asset,
  },
  Asset: {
    interfaces: {
      ip_addresses: {
        network: () => console.log('network resolver called'),
      },
    },
  },
};

但这不起作用,当我运行查询时 - 我没有看到控制台日志。

进一步测试

我想确保如果解析器位于查询返回类型的根级别,则始终会调用它。

我的假设:

Asset: {
    properties: () => console.log('properties - will be called'), // This will get called
    interfaces: {
      created: () => console.log('created - wont be called'),
      ip_addresses: {
        network_id: () => console.log('network - wont be called'),
      },
    },

  },

果然我的控制台显示了

properties - will be called

令人困惑的部分

但不知何故,apollo 仍在为 created 和 ip_addresses 使用默认解析器,因为我可以在 Playground 中看到返回的数据。

解决方法

我可以按如下方式实现“单体”解析器:

Asset: {
    interfaces,
  },

接口解析器在哪里做这样的事情:

export const interfaces = ({ interfaces }) =>
  interfaces.map(interfaceObj => ({ ...interfaceObj, ip_addresses: ip_addresses(interfaceObj) }));

export const ip_addresses = ({ ip_addresses }) =>
  ip_addresses.map(ipAddressObj => ({
    ...ipAddressObj,
    network: network(null, { id: ipAddressObj.network_id }),
  }));

但我觉得这应该由默认解析器处理,因为这些自定义解析器实际上并没有做任何事情,而是将数据传递给另一个解析器。

【问题讨论】:

    标签: apollo apollo-server


    【解决方案1】:

    传递给ApolloServer 构造函数的解析器映射是一个对象,其中每个属性都是架构中类型 的名称。此属性的值是另一个对象,其中每个属性都是该类型的 字段。然后,这些属性中的每一个都映射到该指定字段的解析器函数。

    您发布了一个查询而没有发布您的实际架构,因此我们不知道您的任何类型的实际名称,但假设 network 字段为 Network,您的解析器映射需要看起来像:

    const resolver = {
      // ... other types like Query, IPAddress, etc. as needed
      Network: {
        name: () => 'My network name'
      } 
    }
    

    当然,您可以为架构中的任何字段引入解析器。如果该字段返回一个对象类型,则您返回一个 JavaScript 对象,并且可以让默认解析器逻辑处理解析“更深”的字段:

    const resolvers = {
      IPAddress: {
        network: () => {
          return {
            name: 'My network name',
          }
        }
      }
    }
    

    或者……

    const resolvers = {
      Interface: {
        ip_addresses: () => {
          return [
            { 
              value: 'Some value',
              network: {
                name: 'My network name',
              },
            },
          ]
        }
      }
    }
    

    覆盖默认解析器的位置仅取决于从根级字段返回的数据何时不再与您的架构匹配。有关默认解析器行为的更详细说明,请参阅this answer

    【讨论】:

      猜你喜欢
      • 2013-06-08
      • 2020-08-29
      • 1970-01-01
      • 1970-01-01
      • 2023-01-07
      • 2018-04-14
      • 2020-01-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多