为啥 GraphQL `implements` 需要复制字段,这是强制性的吗?如果是,根本原因是啥?

Posted

技术标签:

【中文标题】为啥 GraphQL `implements` 需要复制字段,这是强制性的吗?如果是,根本原因是啥?【英文标题】:Why GraphQL `implements` need to duplicate the fields, is that mandatory? If yes, what is the underlying reasons?为什么 GraphQL `implements` 需要复制字段,这是强制性的吗?如果是,根本原因是什么? 【发布时间】:2017-09-12 22:59:44 【问题描述】:

为什么 GraphQL implements 关键字需要重复字段,这是强制性的吗?如文档中的示例:

enum Episode  NEWHOPE, EMPIRE, JEDI 

interface Character 
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]


type Human implements Character 
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
  homePlanet: String


type Droid implements Character 
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
  primaryFunction: String

如果是,根本原因是什么?

因为如果我必须复制,如果我改变了,那么我需要到处改变......

【问题讨论】:

【参考方案1】:

是的,这是强制性的。如果有帮助,请将其视为类似于 Java 类和接口。接口具有类型签名,但不能具有实现。它在你写出所有实现的类中,并且类型签名得到重复。这使您能够在类型签名中选择子类型或协变类型,因此它们可能完全相同相同。

现在假设您正在使用来自 graphql-js 的 javascript 对象创建一个 GraphQL 模式。接口只是字段名称和类型。对象类型定义本身具有“实现”或resolveresolveType 以及其他使其成为可执行架构的属性。

但是,您的示例使用了架构语言,它根本没有“实现”。所以它们几乎是彼此的精确重复。您不必每次都将其全部拼写出来,您可以使用字符串插值来共享部分界面。

const characterFields = `
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
`

const typeDefs = `
  interface Character 
    $characterFields
  

  type Human Implements Character 
    $characterFields
    homePlanet: String
  
`

编辑:类似于 Java 比较,字段可能不是完全相同的类型。正如 RomanHotsiy 指出的那样,您可以使类型不可为空或使用多态类型的子类型。

【讨论】:

非常感谢您的回答和出色的比较,但只能选择一个答案,组合起来最好。 @andy-carlson 有一个包含characterHuman 的公共字段的外部文件,然后添加到像...characterFields 这样的字段有什么区别?【参考方案2】:

是的,根据当前spec,这是强制性的:

对象类型必须为接口中定义的每个字段都包含一个同名字段。

它允许您在派生类型中更精确地指定字段类型。字段可以更改为非空或接口或联合的某些特定子类型。以您为例,假设人类仅与其他人类成为朋友,而对机器人也是如此。那么下面的架构是有效的。

interface Character 
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]


type Human implements Character 
  id: String
  name: String
  friends: [Human] # <- notice Human here
  appearsIn: [Episode]
  homePlanet: String


type Droid implements Character 
  id: String
  name: String
  friends: [Droid!]! # <- specified Droid here + added not null
  appearsIn: [Episode]
  primaryFunction: String

对象字段可能包含未在接口字段中定义的附加参数(但不得要求任何附加参数)。

查看规范了解更多详情:Object type validation

【讨论】:

以上是关于为啥 GraphQL `implements` 需要复制字段,这是强制性的吗?如果是,根本原因是啥?的主要内容,如果未能解决你的问题,请参考以下文章

GraphQL - Nullable 不是可重复的注释类型

为啥 Gradle 4.4/Java 插件中没有“api”方法,而 “implementation” 是可用的?

离开页面时,我得到:未处理的 GraphQL 订阅错误错误:GraphQL 错误:未提供所需类型 xxx 的变量 xx

为啥 GraphQL 查询返回 null?

为啥 GraphQL 查询返回 null?

为啥 GraphQL 查询返回 null?