GraphQLInterfaceType和GraphQLUnionType的真实示例

GraphQLInterfaceType和GraphQLUnionType的真实示例,graphql,graphql-js,Graphql,Graphql Js,我很难理解何时使用GraphQLInterfaceType和GraphQLUnionType 我有RTFMs: 有谁能提供一个真实世界的例子来帮助我理解这个问题吗?GraphQLInterfaceType的语义与大多数程序语言的接口类似。graphql为它添加了更多的行为。类似于检查派生类是否实现了所有字段,动态解析到派生实例。 GraphQLUnionType的语义不是一个Union,而是类似于或(有点像flowtype的类型检查? 一个真实的例子是=>中继的节点设计。 GraphQL

我很难理解何时使用
GraphQLInterfaceType
GraphQLUnionType

我有RTFMs:


有谁能提供一个真实世界的例子来帮助我理解这个问题吗?

GraphQLInterfaceType的语义与大多数程序语言的
接口类似。graphql为它添加了更多的行为。类似于检查派生类是否实现了所有字段,动态解析到派生实例。
GraphQLUnionType
的语义不是一个
Union
,而是类似于
(有点像flowtype的类型检查?
一个真实的例子是=>中继的节点设计。
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或其他东西。也许你也应该看看流,这种用法
Dog | Cat
是一种类型限制)

都是为了帮助你设计一个具有异构类型集的模式,您可以使用这两种方法实现相同的功能,但是当类型基本相同但某些字段不同时,
GraphQLUnionType
更适合,而当类型完全不同且具有完全不同的字段时,
GraphQLUnionType
更适合

最终,是否使用其中一种取决于您的模式设计

对于一个真实的例子,假设您有一个博客列表,但是使用框架a的博客使用用户名和密码作为身份验证,使用框架B的博客使用电子邮件和密码。我们使用
图形接口类型
设计它,如下所示:

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;
}
query MyQuery {
   blogs: {
     url
     password
     ... on BlogA {
       email
     }
     ... on BlogB {
       username
     }
   }
}
query MyQuery {
   blogs: {
     url
     auth {
       ... on AuthA {
         username
         password
       }
       ... on AuthB {
         email
         password
       }
     }
   }
}
当我们创建一个新的博客发送
username
,它将创建一个
BlogA

我们可以这样查询:

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;
}
query MyQuery {
   blogs: {
     url
     password
     ... on BlogA {
       email
     }
     ... on BlogB {
       username
     }
   }
}
query MyQuery {
   blogs: {
     url
     auth {
       ... on AuthA {
         username
         password
       }
       ... on AuthB {
         email
         password
       }
     }
   }
}
现在让我们使用
graphqluontype
获得相同的功能,因为我们更喜欢使用一种类型的博客和两种类型的身份验证方法:

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;
}
我们可以这样查询:

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;
}
query MyQuery {
   blogs: {
     url
     password
     ... on BlogA {
       email
     }
     ... on BlogB {
       username
     }
   }
}
query MyQuery {
   blogs: {
     url
     auth {
       ... on AuthA {
         username
         password
       }
       ... on AuthB {
         email
         password
       }
     }
   }
}
正如您在本例中所看到的,我们通过接口或联合实现了相同的功能,但是根据您的模式设计,其中一个可能更合适


例如,假设您想添加一个同样使用电子邮件和密码的博客框架C。您需要包含另一个字段,以便能够在我们的
resolveBlogType
函数中将其与blog框架B区分开来。让我们添加
type
字段。在我们的联合示例中,由于我们只能访问联合中的字段,因此您需要向联合添加
type
。如果将来我们想为多个框架添加另一个具有相同字段的Union,那么我们还需要在那里添加
type
字段。在我们的模式中重复多次
type
不是件好事。最好使用一个接口,让所有使用接口的对象在
resolveBlogType
函数中都可以访问一个
type
字段。

当您在中继片段上查询
blogs
时,这与graphql相对应的是什么?我看到您的graphql接口类型名为
Blog
,您需要创建
blogs
查询,该查询不在示例代码中。我仍然不确定我是否理解,当使用这个示例时,我得到了错误:
…\node\u modules\graphql\type\schema.js:295
throw\u iteratorerror
^
类型错误:graphQLType.getFields不是一个函数
@AlexanderPravdin它实际上没有显示在文档中,但字段需要是一个返回对象的函数,您可以参考这个非常有用的视频的js部分: