GraphQL 类型组合

Posted

技术标签:

【中文标题】GraphQL 类型组合【英文标题】:GraphQL type composition 【发布时间】:2017-10-06 17:38:56 【问题描述】:

我正在探索 graphql,困扰我的问题是在定义我的 graphql 服务器时是否可以进行某种类型组合。

假设我的收藏中有 Person 和 Company。我有这样的事情:

const Person = new GraphQLObjectType(
  name: 'Person',
  fields: 
    firstName: type: GraphQLString,
    lastName: type: GraphQLString
  
);

const Company = new GraphQLObjectType(
  name: 'Company',
  fields: 
    name: type: GraphQLString,
    website: type: GraphQLString
  
);

但是 Company 和 Person 都应该有如下字段:createdAtid。所以假设我有:

const Entity = new GraphQLObjectType(
  name: 'Entity',
  fields: 
    id: type: GraphQLString,
    createdAt: type: GraphQLString
  
);

所以我在想这样的事情:

new GraphQLObjectType(
  ...
  extends: [Entity]
);

我知道有interfaces,但我认为这不是我想要的,因为无论如何我都需要实现接口,而我想要实现的是单独保留一些字段定义并在其中重复使用它们其他类型。

有什么想法吗?我是在尝试做一些完全没有意义的事情吗?

【问题讨论】:

【参考方案1】:

如果我们查看 GraphQL 语言规范,就会发现接口。接口用于描述两种类型的常见行为。接口通常只有在同一字段中返回两个子类型时才有意义。 GraphQL documentation 有一个很好的例子。我建议不要在您的情况下使用接口,除非您想在同一字段中返回所有实体类型(例如在搜索中)。

您在谈论服务器实现级别。我不知道如何在 GraphQL.js 中扩展这样的类型。您可以做的是创建一个包含两个字段的 javascript 对象。然后,您可以重用此代码并将其插入到每种类型中,例如使用Object.assign

  const standardFields = 
    id: 
      type: new GraphQLNonNull(GraphQLID),
      description: 'Unique id for this entity'
    ,
    createdAt: 
      type: new GraphQLNonNull(GraphQLString),
      description: 'Datetime of this entity\'s creation'
    
  

  const Company = new GraphQLObjectType(
    name: 'Company',
    fields: Object.assign(, standardFields, 
      name: type: GraphQLString,
      website: type: GraphQLString
    
  );

或者可能从文件中导入字段并显式插入:

  const  id, createdAt  = require('./standardFields');

  const Company = new GraphQLObjectType(
    name: 'Company',
    fields: 
      id,
      createdAt,
      name: type: GraphQLString,
      website: type: GraphQLString
    
  );

在这两种情况下,我都没有从中获得太多收益。设置一个确保所有类型都包含字段的测试可能更有用。

【讨论】:

这正是我目前正在做的,但我不太喜欢这个解决方案,因为在这种情况下 idcreatedAt 不是独立的。 这可能是一个典型的“继承或组合”问题。您正在寻找的每种模式都没有在实际的 API 中表示。所以我们不得不问这两者的意义是什么。避免代码重复?可测试性?如果不仅仅是为了继承,你为什么要在这里寻找遗产?我不会太担心它,在我们的应用程序中,我们实际上明确地重复了这些字段。这为我们提供了具有显式依赖关系的易于理解的代码。 关键部分:“接口通常只有在同一字段中返回两个子类型时才有意义。” GraphQL 确实允许 type extension【参考方案2】:

您可以像这样从interface 类型中获取字段:

const carInterface = new GraphQLInterfaceType(
  name: 'car',
  fields: 
    _id:  type: GraphQLID ,
    userId:  type: GraphQLID ,
    carType:  type: new GraphQLNonNull(GraphQLString), description: 'نوع اعلان السيارة' ,
    title:  type: new GraphQLNonNull(GraphQLString), description: 'عنوان الاعلان' ,
    brand:  type: GraphQLString, description: 'الماركة-النوع' ,
    model:  type: GraphQLString, description: 'الموديل' 
   
);
console.log(carInterface._typeConfig.fields);

您可以轻松地将carInterface._typeConfig.fields 添加到任何GraphQLObject 字段定义中;

【讨论】:

以上是关于GraphQL 类型组合的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL 变量组合验证

在 GatsbyJS/GraphQL 中组合页面查询

Apollo GraphQL技术栈概览:如何将所有的功能组合起来

GraphQL 是不是具有与 REST 相同的缓存能力

Python GraphQL API 调用组合

Python GraphQL API 调用组合