15

我很难理解何时使用GraphQLInterfaceTypeand GraphQLUnionType

我有 RTFM:

任何人都可以提供一个真实世界的例子,当这些对我的厚脑袋有用时?

4

2 回答 2

32

两者都旨在帮助您设计具有一组异构类型的模式,并且您可以使用两者来实现相同的功能,但是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在我们的模式中重复多次并不太好。使用接口可能是一个更好的主意,并且使用该接口的所有对象都可以在函数中访问单个type字段。resolveBlogType

于 2016-05-09T12:30:51.667 回答
2

GraphQLInterfaceType语义就像大多数程序语言的interface. 并且 graphql 为它添加了更多的行为。比如检查派生类是否实现了所有字段,动态解析派生实例。
的语义GraphQLUnionType不是一个Union,而是类似的东西OR。(有点像流类型的类型检查?)
一个真实的例子是Relay => Relay 的节点设计中的例子。
GraphQLInterfaceType与 完全无关GraphQLUnionType
我想也许你对此感到困惑?

interface Node{
  id: string
}

type Dog implements Node{
  id: string
}
type Cat implements Node{
  id: string 
}
union Animal = Dog | Cat

type User{
  node: Node
  animal: Animal
}

如果对此感到困惑,您应该阅读一些强类型语言的书。(如 C# 或 Java 或其他东西。也许您也应该看看 Flow,这种用法Dog|Cat是类型限制)

于 2016-02-02T08:52:25.260 回答