GraphQLInterfaceType和GraphQLUnionType的真实示例

时间:2016-01-11 16:39:12

标签: graphql graphql-js

我很难理解何时使用GraphQLInterfaceTypeGraphQLUnionType

我有RTFM:

任何人都可以提供一个真实世界的例子,当这些有用的时候可以让我通过我的头脑吗?

2 个答案:

答案 0 :(得分:26)

两者都旨在帮助您设计具有异构类型集的模式,并且您可以使用两者来实现相同的功能,但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
       }
     }
   }
}

正如您在本示例中所看到的,我们使用接口或union实现了相同的功能,但根据您的架构设计,其中一个可能更合适。

例如,假设您要添加一个也使用电子邮件和密码的博客框架C.您需要包含另一个字段,以便能够在我们的resolveBlogType函数中将其与博客框架B区分开来。我们添加type字段。在我们的Union示例中,由于我们只能访问Union中的字段,因此您可以将type添加到Union。如果将来我们想为多个框架添加另一个具有相同字段的Union,我们还需要在那里添加type字段。在我们的架构中多次重复type不太好。使用接口可能是一个更好的主意,并且所有使用接口的对象都可以在type函数访问单个resolveBlogType字段。

答案 1 :(得分:2)

GraphQLInterfaceType的抒情诗就像大多数程序语言interface一样。和graphql为它添加一些更多的行为。比如检查派生类是否实现了所有字段,动态解析为派生实例 GraphQLUnionType的抒情诗不是Union,而是OR。(有点像flowtype的类型检查?)
一个真实的例子是example in Relay =>继电器的节点设计。
GraphQLInterfaceTypeGraphQLUnionType完全无关 我想也许你对此感到困惑?

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是一种类型限制)