两者都旨在帮助您设计具有一组异构类型的架构,并且您可以使用两者实现相同的功能,但GraphQLInterfaceType 更适合类型基本相同但某些字段不同的情况, 和GraphQLUnionType 当类型完全不同并且具有完全不同的字段时。
最终是否使用其中一个取决于您的架构设计。
对于一个真实的例子,假设你有一个博客列表,但是使用框架 A 的博客使用用户名和密码作为身份验证,使用框架 B 的博客使用电子邮件和密码。我们使用GraphQLInterfaceType 设计它,如下所示:
const BlogType = new GraphQLInterfaceType({
name: 'Blog',
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
password: { type: new GraphQLNonNull(GraphQLString) }
},
resolveType: resolveBlogType
});
const BlogAType = new GraphQLObjectType({
name: 'BlogA',
interfaces: [Blog],
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
username: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
const BlogBType = new GraphQLObjectType({
name: 'BlogB',
interfaces: [Blog],
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
email: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
function resolveBlogType(value) {
return value.username ? BlogAType : BlogBType;
}
当我们创建一个发送username的新博客时,它会创建一个BlogA。
我们可以这样查询:
query MyQuery {
blogs: {
url
password
... on BlogA {
email
}
... on BlogB {
username
}
}
}
现在让我们使用 GraphQLUnionType 获得相同的功能,因为我们更喜欢只使用一种类型的博客和两种类型的身份验证方法:
const AuthAType = new GraphQLObjectType({
name: 'AuthA',
fields: {
username: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
const AuthBType = new GraphQLObjectType({
name: 'AuthB',
fields: {
email: { type: new GraphQLNonNull(GraphQLString) },
password: { type: new GraphQLNonNull(GraphQLString) }
}
});
const AuthType = new GraphQLUnionType({
name: 'Auth',
types: [AuthAType, AuthBType]
resolveType: resolveAuthType
});
const BlogType = new GraphQLInterfaceType({
name: 'Blog',
fields: {
url: { type: new GraphQLNonNull(GraphQLString) }
auth: { type: AuthType }
},
});
function resolveAuthType(value) {
return value.username ? AuthAType : AuthBType;
}
我们可以这样查询:
query MyQuery {
blogs: {
url
auth {
... on AuthA {
username
password
}
... on AuthB {
email
password
}
}
}
}
正如您在此示例中所见,我们使用接口或联合实现了相同的目的,但根据您的架构设计,其中一种可能更合适。
例如,假设您要添加一个博客框架 C,该框架也使用电子邮件和密码。您需要在我们的resolveBlogType 函数中包含另一个字段,以便能够将其与博客框架 B 区分开来。让我们添加type 字段。在我们的联合示例中,由于我们只能访问联合中的字段,因此您需要将 type 添加到联合中。如果将来我们想为多个框架添加另一个具有相同字段的联合,我们还需要在其中添加 type 字段。 type 在我们的模式中重复多次并不太好。使用接口可能是一个更好的主意,并且使用该接口的所有对象都可以在 resolveBlogType 函数中访问单个 type 字段。