深度大于1的嵌套分解器

时间:2019-07-02 11:43:18

标签: apollo apollo-server

问题

查看此GraphQL查询

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

如何为ip_addresses上的网络 字段定义解析器?

我的第一个念头

阅读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

令人困惑的部分

但是以某种方式,阿波罗仍在使用默认的解析器来创建和ip_addresses,因为我可以在操场上看到返回的数据。

解决方法

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

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

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

1 个答案:

答案 0 :(得分:1)

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

您发布的查询没有发布您的实际架构,因此我们不知道您的任何类型实际被命名为什么,但是假设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