合并 Apollo 服务器的 GraphQL 解析器不使用 Object.assign()

Posted

技术标签:

【中文标题】合并 Apollo 服务器的 GraphQL 解析器不使用 Object.assign()【英文标题】:Merging GraphQL Resolvers for Apollo Server not working with Object.assign() 【发布时间】:2018-01-05 03:40:39 【问题描述】:

我正在为 GraphQL API 模块化我的架构,并尝试在不使用任何 3rd 方库的情况下合并解析器。

如果没有Lodash.merge() 或等效项,有没有一种简单的方法可以做到这一点?

Apollo 文档说要使用 Lodash 之类的库来 merge() 模块化解析器。 (http://dev.apollodata.com/tools/graphql-tools/generate-schema.html#modularizing)

问题似乎在于,解析器本质上包含作为属性的函数,因此当我通过Object.assign() 甚至JSON.stringify() 访问它们时,它们似乎被省略了。

如果我控制台记录它们,我会看到:"Query":,"Mutation":

这是其中一个解析器的样子:

 const productResolvers = 
   Query: 
     myProducts: (root,  userId , context) => 
       return [
          id: 1, amount: 100, expiry: '12625383984343', created: '12625383984343' ,
          id: 2, amount: 200, expiry: '12561351347311', created: '12625383984343' ,
          id: 3, amount: 200, expiry: '11346347378333', created: '12625383984343' ,
          id: 4, amount: 350, expiry: '23456234523453', created: '12625383984343' ,
       ];
     ,
   ,
   Mutation: 
     addProduct: (root,  userId , context) => 
       return  id: 350, amount: 100, expiry: '12625383984343', created: '12625383984343' ;
     ,
   
 ;

让我们假设有另一个几乎相同的名称widgetResolvers

这是一个功能齐全的代码块:

 export const schema = makeExecutableSchema(
   typeDefs: [queries, mutations, productSchema, widgetSchema],
   resolvers
 );

这是我想要实现的目标:

 export const schema = makeExecutableSchema(
   typeDefs: [queries, mutations, productSchema, widgetSchema],
   resolvers: Object.assign(, productResolvers, widgetResolvers)
 );

我还没有加载使用 rest spread 的能力 (https://babeljs.io/docs/plugins/transform-object-rest-spread/)。我怀疑它不会因为 Object.assign() 不起作用的相同原因而起作用。

哦,这就是我怀疑此合并不起作用的原因:Why doesn't JSON.stringify display object properties that are functions?

【问题讨论】:

我正在使用 Lodash merge(),直至另行通知。效果很好。 【参考方案1】:

如果您使用Object.assign(),您的 Query 和 Mutation 属性不应为空,但您会遇到问题,因为与 lodash 的 merge() 不同,它不是递归的。 Object.assign() 只比较它所传递的对象的“直接”属性——当它在列表中移动时覆盖先前源的属性。

因为QueryMutation 是被传递对象的属性,每个后续的解析器都会覆盖前一个对象的QueryMutation,结果对象只包含最后一个传递对象的查询和突变属性进入Object.assign()

它不那么整洁,但如果你一心要避免导入 lodash,你可以通过这种方式获得预期的行为:

const productResolver = 
  Query:  ... ✂ ... ,
  Mutation:  ... ✂ ... 


const widgetResolver = 
  Query:  ... ✂ ... ,
  Mutation:  ... ✂ ... 


const resolvers = 
  Query: Object.assign(, widgetResolver.Query, productResolver.Query),
  Mutation: Object.assign(, widgetResolver.Mutation, productResolver.Mutation)

也有类型解析器?没问题:

const Widget =  ... ✂ ... 
const Product =  ... ✂ ... 

const resolvers = Object.assign(
  
    Query: Object.assign(, widgetResolver.Query, productResolver.Query),
    Mutation: Object.assign(, widgetResolver.Mutation, productResolver.Mutation)
  ,
  Widget,
  Product)

【讨论】:

谢谢,非常有帮助。 我会保留 Lodash,因为我怀疑如果我使用 Object.assign() 只是为了保持它的原生性,那么非递归性质有一天会拖累我。 是的,Lodash 非常有用。我认为,如果您查看他们的文档,您也会发现库中许多其他方法的用途。如果你想避免只使用一种方法导入整个库,你也可以import the methods one module at a time :)

以上是关于合并 Apollo 服务器的 GraphQL 解析器不使用 Object.assign()的主要内容,如果未能解决你的问题,请参考以下文章

(Apollo) GraphQL 合并模式

如何在 apollo graphql 服务器中编写解析 graphql 过滤器

如何使用 Apollo 分离 GraphQL 模式和解析器文件?

Graphql apollo 服务器解析器参数类型

Graphql Apollo Federation - 基于实现服务解析计算域

Apollo GraphQL 服务器:按单独解析的字段过滤(或排序)