在 GraphQL 中,接口(InterfaceTypeDefinition)也是一种命名字段集合,定义规则与对象类型极其相似,同样支持 字段名、类型、参数 三要素。
与 OOP 概念类似,GraphQL 中的接口只是对资源的抽象描述,必须被其他对象类型实现,才能正常使用。我们来看个例子:
interface NamedEntity {
name: String
}
type User implements NamedEntity {
id: ID!
name: String
}
上例中,NamedEntity
即为接口;User
是实现了该接口的对象类型。注意,实现类必须实现接口的所有字段,字段名、类型、参数都必须与接口匹配。
GraphQL 支持多继承:
interface NamedEntity {
name: String
}
interface Node {
id: ID!
}
'''
非法示例:
没有实现Node接口的id字段
'''
type User implements NamedEntity & Node {
name: String
}
那么,在什么场景下应该使用接口?我们要理解,接口是对资源的抽象描述,不一定完备、详尽,但往往能表述多类相似资源的共同特征,所以如果服务中存在一些具备共性的类型,而用户需要关注共同的这一部分,就应该使用接口。
比如,我们有三种类型的商品:饮料、图书、电器:
type Drinks {
id: ID!
name: String!
price: Float!
'''
容量,单位为ml
'''
capacity: Float!
}
type Book {
id: ID!
name: String!
price: Float!
'''
作者
'''
author: [People]
issn: String!
}
type ElectricalEquipment {
id: ID!
name: String!
price: Float!
'''
生产商
'''
manufacturer: Company
}
上面三个商品对象有三个相似的属性:id
、name
、price
,是商品资源的不同类型。现在,我们需要实现根据名称搜索商品,如果接口功能,就必须使用近似的逻辑,在三种类型节点上,重复定义三次;如果未来我们增加更多公共查询逻辑,我们又得把逻辑重复三遍,这显然不是一个好的设计。这种情况下就适合使用接口,将三个公共字段抽取出来,再以接口类型对外暴露商品的聚合查询节点:
interface Item {
id: ID!
name: String!
price: Float!
}
type Drinks implements Item{ ... }
type Book implements Item{ ... }
type ElectricalEquipment implements Item{ ... }
type Query {
'''
商品列表,支持按商品名查询
'''
items(name: Sring): [Item]
}
而对于客户端来说,针对接口节点的查询,除了接口的属性外,也支持查询实现类的字段:
query {
items(name: 'coka') {
name
... on Drinks {
capacity
}
}
}
代码片段 ... on Drinks { capacity }
,被称为 Inline Fragments。
针对这段查询,引擎会帮助判断如果解析结果为 Drinks
类型,则返回 capacity
字段;如果是其他类型的商品,则不做进一步处理,不会返回 capacity
,也不报错。有兴趣的读者,可以到 GraphQL 接口示例代码 看看。
注意,GraphQL 引擎没有检测类型的能力,开发者必须为接口节点提供
resolveType
函数,以在运行时指定解析结果的类型!否则会报错:Abstract type NamedEntity must resolve to an Object type at runtime for field Query.users with value { id: 1, name: \"foo\", age: 1, type: \"User\" }, received \"undefined\". Either the NamedEntity type should provide a \"resolveType\" function or each possible type should provide an \"isTypeOf\" function.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。