GraphQLInterfaceType 中的接口是什么?
What does the interfaces in GraphQLInterfaceType?
我有以下代码片段:
export const NodeInterface = new GraphQLInterfaceType({
name: 'Node',
fields: {
id: {
type: new GraphQLNonNull(GraphQLID)
}
},
resolveType: (source) => {
if (source.__tableName === tables.users.getName()) {
return UserType;
}
return PostType;
}
});
和一个正在使用接口的GraphQLObjectType
:
export const PostType = new GraphQLObjectType({
name: 'Post',
interfaces: [ NodeInterface ],
fields: {
id: {
type: new GraphQLNonNull(GraphQLID),
resolve: resolveId
},
createdAt: {
type: new GraphQLNonNull(GraphQLString),
},
body: {
type: new GraphQLNonNull(GraphQLString)
}
}
});
为什么我必须定义接口?
在 GraphQL 中,接口实现两个目的:
它们确保实现它们的类型也实现了特定的字段。例如,这里的 Node
接口有一个 id
字段——这意味着任何实现 Node
接口的类型也需要有一个 id
字段(并且 id
将需要像接口中那样是一个 ID 标量)这些参数也是如此——接口中字段上的任何参数也必须存在于实现类型中的匹配字段上。
当一个字段需要两种或多种类型时,可以使用它们。一个字段将总是解析为一个类型或标量,但是,通过使用接口(或联合),我们在我们的模式中表明该字段可以解析为一组类型中的一种。
所以假设我们在您的代码段中有一个 Node
,一些实现它的类型,以及一个 returns 节点的查询:
interface Node {
id: ID!
}
type Foo implements Node {
id: ID!
someFooField: String!
someOtherFooField: Int!
}
type Bar implements Node {
id: ID!
someBarField: String!
someOtherFooField: Int!
}
type Query {
getNode(id: ID!): Node!
}
在我们的示例中,getNode
可以解析为 Foo
或 Bar
。当我们编写我们的查询时,我们不知道哪一个会被解决。但是因为我们知道接口需要id
这个字段,所以我们可以这样写一个查询:
query OperationName {
getNode(id: "SOME_ID"){
id
}
}
如果我们也需要查询 someBarField
,但是,我们不能这样做:
query OperationName {
getNode(id: "SOME_ID"){
id
someBarField
}
}
因为 Foo
没有那个字段。相反,我们必须使用一个片段,如下所示:
query OperationName {
getNode(id: "SOME_ID"){
id
... on Bar {
someBarField
}
}
}
然后 someBarField
将被返回,但前提是该字段解析为类型 Bar
。如果是 Foo
,则只返回 id。同样,您可以从实现相同接口的任何类型请求 non-shared 字段:
query OperationName {
getNode(id: "SOME_ID"){
id
... on Bar {
someBarField
}
... on Foo {
someFooField
}
}
}
最后但同样重要的是,工会的工作方式非常相似。但是,与接口不同的是,联合没有定义共享字段,因此类型不是 "implement" 联合,它只是联合的一部分。这意味着当请求一个 returns 联合的字段时,您将始终必须使用片段,因为没有要请求的共享字段。
我有以下代码片段:
export const NodeInterface = new GraphQLInterfaceType({
name: 'Node',
fields: {
id: {
type: new GraphQLNonNull(GraphQLID)
}
},
resolveType: (source) => {
if (source.__tableName === tables.users.getName()) {
return UserType;
}
return PostType;
}
});
和一个正在使用接口的GraphQLObjectType
:
export const PostType = new GraphQLObjectType({
name: 'Post',
interfaces: [ NodeInterface ],
fields: {
id: {
type: new GraphQLNonNull(GraphQLID),
resolve: resolveId
},
createdAt: {
type: new GraphQLNonNull(GraphQLString),
},
body: {
type: new GraphQLNonNull(GraphQLString)
}
}
});
为什么我必须定义接口?
在 GraphQL 中,接口实现两个目的:
它们确保实现它们的类型也实现了特定的字段。例如,这里的
Node
接口有一个id
字段——这意味着任何实现Node
接口的类型也需要有一个id
字段(并且id
将需要像接口中那样是一个 ID 标量)这些参数也是如此——接口中字段上的任何参数也必须存在于实现类型中的匹配字段上。当一个字段需要两种或多种类型时,可以使用它们。一个字段将总是解析为一个类型或标量,但是,通过使用接口(或联合),我们在我们的模式中表明该字段可以解析为一组类型中的一种。
所以假设我们在您的代码段中有一个 Node
,一些实现它的类型,以及一个 returns 节点的查询:
interface Node {
id: ID!
}
type Foo implements Node {
id: ID!
someFooField: String!
someOtherFooField: Int!
}
type Bar implements Node {
id: ID!
someBarField: String!
someOtherFooField: Int!
}
type Query {
getNode(id: ID!): Node!
}
在我们的示例中,getNode
可以解析为 Foo
或 Bar
。当我们编写我们的查询时,我们不知道哪一个会被解决。但是因为我们知道接口需要id
这个字段,所以我们可以这样写一个查询:
query OperationName {
getNode(id: "SOME_ID"){
id
}
}
如果我们也需要查询 someBarField
,但是,我们不能这样做:
query OperationName {
getNode(id: "SOME_ID"){
id
someBarField
}
}
因为 Foo
没有那个字段。相反,我们必须使用一个片段,如下所示:
query OperationName {
getNode(id: "SOME_ID"){
id
... on Bar {
someBarField
}
}
}
然后 someBarField
将被返回,但前提是该字段解析为类型 Bar
。如果是 Foo
,则只返回 id。同样,您可以从实现相同接口的任何类型请求 non-shared 字段:
query OperationName {
getNode(id: "SOME_ID"){
id
... on Bar {
someBarField
}
... on Foo {
someFooField
}
}
}
最后但同样重要的是,工会的工作方式非常相似。但是,与接口不同的是,联合没有定义共享字段,因此类型不是 "implement" 联合,它只是联合的一部分。这意味着当请求一个 returns 联合的字段时,您将始终必须使用片段,因为没有要请求的共享字段。