接口类型
|
这是 GraphQL Library 7 版本的文档。对于长期支持 (LTS) 版本 5,请参考 GraphQL Library 5 LTS 版本。 |
本页介绍了如何在关系背景下使用接口,并举例说明了如何在查询和变更(Mutations)中使用它们。
数据模型
以如下图形为例,其中 Person 类型具有两种不同的关系类型,可以将其连接到 Movie 和 Series 类型。ACTED_IN 关系根据目标节点类型的不同而具有不同的属性。
示例数据库数据
考虑一个由以下示例数据组成的数据库,它遵循上述数据模型。
接口上的关系
Movie 和 Series 类型非常相似。它们的共同点可以通过定义一个 Production 接口来捕获,该接口由 Movie 和 Series 同时实现,并在该接口上声明 actors 关系字段。
这使您可以从接口查询关系,同时支持在具体类型中定义关系详情(如类型和属性)的灵活性。
@declareRelationship
@relationship 指令只能用于对象类型的字段。
如果您想在接口上建模关系,并由具体的对象类型来实现,可以使用 @declareRelationship 指令。
interface Production {
title: String!
actors: [Person!]! @declareRelationship
}
type Person @node {
name: String!
}
实现已声明的关系
实现 Production 接口的具体类型必须定义自己的关系详情,例如类型和属性。这既捕获了它们的细微差别,又可以作为 Production 接口的字段进行查询。
请注意 ACTED_IN 关系在 ActedInSeries 和 ActedIn 之间有何不同。
Movie 和 Series 实现 Production 接口来扩展类型定义interface Production {
title: String!
actors: [Person!]! @declareRelationship
}
type Movie implements Production @node {
title: String!
released: Int!
actors: [Person!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN)
}
type Series implements Production @node {
title: String!
episodes: Int!
actors: [Person!]! @relationship(type: "ACTED_IN", properties: "ActedInSeries", direction: IN)
}
type ActedIn @relationshipProperties {
roles: [String!]!
}
type ActedInSeries @relationshipProperties {
roles: [String!]!
episodes: [Int!]!
}
type Person @node {
name: String!
}
|
声明的关系必须在实现该接口的所有具体类型中实现,就像接口类型上的任何其他字段一样。例如, |
查询接口关系
当查询接口上声明的关系字段时,虽然可以从接口级别访问关系字段,但返回的数据基于实现该接口的具体类型。
Person 类型# Top-level interface query fields
productions(limit: Int, offset: Int, sort: [ProductionSort!], where: ProductionWhere): [Production!]!
productionsConnection(after: String, first: Int, sort: [ProductionSort!], where: ProductionWhere): ProductionsConnection!
# Top-level concrete type query fields
movies(limit: Int, offset: Int, sort: [MovieSort!], where: MovieWhere): [Movie!]!
moviesConnection(after: String, first: Int, sort: [MovieSort!], where: MovieWhere): MoviesConnection!
series(limit: Int, offset: Int, sort: [SeriesSort!], where: SeriesWhere): [Series!]!
seriesConnection(after: String, first: Int, sort: [SeriesSort!], where: SeriesWhere): SeriesConnection!
重点关注 productions 和 productionsConnection 查询字段。
此查询返回最多 10 个制作内容的排序列表(即 Movie 和 Series 节点的混合),以及它们的相关演员。
注意使用内联片段(inline fragments)来访问特定于具体类型的字段。
query {
productions(limit: 10, sort: { title: ASC }) {
title
... on Movie {
released
}
actors {
name
}
}
}
假设使用本页的示例数据,查询结果如下
{
"data": {
"productions": [
{
"title": "Argo",
"released": 2012,
"actors": [{ "name": "Ben Affleck" }],
},
{
"title": "Gone Girl",
"released": 2014,
"actors": [{ "name": "Ben Affleck" }],
},
{
"title": "The Voyage of the Mimi",
"actors": [{ "name": "Ben Affleck" }],
},
{
"title": "Buffy the Vampire Slayer",
"actors": [{ "name": "Ben Affleck" }],
},
],
}
}
上面的查询返回最多 10 个制作内容的排序列表(即 Movie 和 Series 节点的混合),以及它们的相关演员和 ACTED_IN 关系的属性。
由于存在不同的关系属性类型(ActedIn 和 ActedInSeries),查询必须使用内联片段来访问关系属性。
query {
productionsConnection(first: 10, sort: [{ title: ASC }]) {
edges {
node {
title
actorsConnection(first: 2, sort: { node: { name: ASC } }) {
edges {
node {
name
}
properties {
... on ActedIn {
roles
}
... on ActedInSeries {
roles
episodes
}
}
}
}
}
}
}
}
假设使用本页的示例数据,查询响应如下
{
"data": {
"productionsConnection": {
"edges": [
{
"node": {
"title": "Argo",
"actorsConnection": {
"edges": [{
"node": {
"name": "Ben Affleck",
},
"properties": {
"roles": ["Tony Mendez"],
},
}],
},
},
},
{
"node": {
"title": "Buffy the Vampire Slayer",
"actorsConnection": {
"edges": [{
"node": {
"name": "Ben Affleck",
},
"properties": {
"roles": ["Basketball Player #10"],
"episodes": 1,
},
}],
},
},
},
{
"node": {
"title": "Gone Girl",
"actorsConnection": {
"edges": [{
"node": {
"name": "Ben Affleck",
},
"properties": {
"roles": ["Nick Dunne"],
},
}],
},
},
},
{
"node": {
"title": "The Voyage of the Mimi",
"actorsConnection": {
"edges": [{
"node": {
"name": "Ben Affleck",
},
"properties": {
"roles": ["C.T. Granville"],
"episodes": 7,
},
}],
},
},
},
],
},
},
}
指向接口的关系
对于本章开头描述的数据模型,Person 类型节点已连接到 Movie 和 Series 节点,但此关系尚未在 GraphQL 模式中建模。
您可以通过向 Person 类型添加指向 Production 接口的关系字段,然后在具体类型中实现关系详情来实现这一点。
Person 类型type Person @node {
name: String!
born: Int!
# relationship to an interface
actedIn: [Production!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: OUT)
}
查询接口的关系
当查询接口类型的关系字段时,可以直接查询接口字段,因为它们在概念上由该接口的所有实现共享,例如 Production 的 title。
要查询实现接口的具体类型特有的字段,必须使用内联片段,例如 Movie 的 released 和 Series 的 episodes。
注意使用内联片段来访问 Movie 和 Series 具体类型的特定字段。
query {
people {
name
actedIn {
title
... on Movie {
released
}
... on Series {
episodes
}
}
}
}
过滤接口的具体实现
当查询接口类型的关系字段时,不一定要接收所有实现类型的节点。如果需要,您可以使用 typename 过滤器请求特定的节点类型。
注意 typename 过滤器以及使用内联片段来访问具体类型 Movie 的特定字段。
query {
people {
name
actedIn(where: { typename: [Movie] }) {
title
... on Movie {
released
}
}
}
}
创建指向接口的关系
创建指向接口类型的关系时,必须在变更中指定要连接的节点的具体类型。
注意所创建节点的具体类型(Movie 或 Series)的规范。
mutation CreateActorAndProductions {
createPeople(
input: [
{
name: "Ben Affleck"
actedIn: {
create: [
{
edge: { roles: ["Tony Mendez"] }
node: { Movie: { title: "Argo", released: 2012 } }
}
{
edge: { roles: ["Nick Dunne"] }
node: { Movie: { title: "Gone Girl", released: 2014 } }
}
{
edge: { roles: ["Basketball Player #10"] }
node: { Series: { title: "Buffy the Vampire Slayer", episodes: 144 } }
}
{
edge: { roles: ["C.T. Granville"] }
node: { Series: { title: "The Voyage of the Mimi", episodes: 7 } }
}
]
}
}
]
) {
people {
name
}
}
}
更新指向接口的关系
对接口的操作适用于所有实现该接口的具体类型,除非您对其进行了限制。
下面的变更将新发行的 Movie "Henry Danger" 添加到数据库中,并通过角色为 "Henry Hart" 的 ACTED_IN 关系将其连接到 Person 节点 Jace Norman。请注意,标题相同的 Series 节点已经存在。
要实现所需的连接,请在更新变更的过滤器中使用 typename 过滤器。
注意使用 typename 过滤器仅针对 Movie 节点。
mutation {
updatePeople(
where: { name: { eq: "Jace Norman" } }
update: {
actedIn: [
{
connect: [
{
edge: { roles: ["Henry Hart"] }
where: {
node: {
typename: [Movie],
title: { eq: "Henry Danger" }
},
},
},
],
},
],
}
) {
info {
relationshipsCreated
}
}
}
如果 Person 和 Movie 之间的关系已存在于数据库中,请确保关系属性根据所连接节点的类型是正确的。
注意边缘属性会根据所连接节点的 typename 更新为不同的值。
mutation {
updatePeople(
where: {
name: {
eq: "Jace Norman"
}
}
update: {
actedIn: [
{
update: {
where: { node: { title: { eq: "Henry Danger" } } }
node: {
actors: [
{
update: {
edge: {
ActedIn: { roles: { set: ["Henry Hart"] } },
ActedInSeries: { roles: { set: ["Henry Hart"] }, episodes: { set: 121 } },
},
},
},
],
},
},
}]
}
) {
info {
relationshipsCreated
}
}
}