深度大于 1 的嵌套解析器

Nested resolvers with depth greater than 1

问题

查看此 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'),
      },
    },
  },
};

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

进一步测试

我想确保解析器在查询 return 类型的根级别上始终被调用。

我的假设:

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 仍然使用默认解析器来创建和 ip_addresses,正如我在 playground 中看到的 returned 数据。

解决方法

我可以按如下方式实现 "monolith" 解析器:

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 }),
  }));

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

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

您在没有发布实际架构的情况下发布了查询,因此我们不知道您的任何类型实际命名的是什么,但假设 network 字段是 Network,您的解析器映射需要类似于:

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

当然,您可以为架构中的任何字段引入解析器。如果字段 return 是一个对象类型,您 return 一个 JavaScript 对象并且可以让默认解析器逻辑处理解析 "deeper" 字段:

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

或者...

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

您在何处覆盖默认解析器仅取决于从您的 root-level 字段中 return 编辑的数据在什么时候不再与您的架构匹配。有关默认解析器行为的更详细说明,请参阅