buildSchema和GraphQLSchema之间的显著差异?

buildSchema和GraphQLSchema之间的显著差异?,graphql,graphql-js,Graphql,Graphql Js,这两者之间有什么显著的区别吗?我对任何东西都感兴趣,从运行时和启动性能到功能和工作流差异。文档在解释差异以及何时应该使用其中一个而不是另一个方面做得很差 两个版本中的示例: 构建模式 const{graphql,buildSchema}=require('graphql'); const schema=buildSchema(` 类型查询{ 你好:字符串 } `); const root={hello:()=>“hello world!”}; graphql(模式,{hello}',根)。然后(

这两者之间有什么显著的区别吗?我对任何东西都感兴趣,从运行时和启动性能到功能和工作流差异。文档在解释差异以及何时应该使用其中一个而不是另一个方面做得很差

两个版本中的示例: 构建模式
const{graphql,buildSchema}=require('graphql');
const schema=buildSchema(`
类型查询{
你好:字符串
}
`);
const root={hello:()=>“hello world!”};
graphql(模式,{hello}',根)。然后((响应)=>{
控制台日志(响应);
});
图形模式
const{graphql,GraphQLSchema,GraphQLObjectType,GraphQLString}=require('graphql');
const schema=new GraphQLSchema({
查询:新的GraphQLObjectType({
名称:“查询”,
字段:()=>({
您好:{
类型:GraphQLString,
解析:()=>“你好,世界!”
}
})
})
});
graphql(模式,{hello}')。然后((响应)=>{
控制台日志(响应);
});

buildSchema函数采用SDL(模式定义语言)中的模式,并返回一个
GraphQLSchema
对象。给定使用每个方法生成的两个相同的模式,运行时性能将是相同的。使用
buildSchema
的服务器的启动时间会慢一些,因为解析SDL会增加一个额外的步骤,而这在其他情况下是不存在的——是否会有明显的区别,我不能确定地说

使用
buildSchema
通常是不可取的,因为它严重限制了模式的功能。

使用
buildSchema
生成的架构:

  • 无法为单个字段指定解析函数
  • 无法为类型指定
    resolveType
    isTypeOf
    属性,因此无法使用
    联合
    接口
  • 无法使用自定义标量
第#1项强调的力度不够--
buildSchema
不允许您为架构中的任何字段指定解析器函数。这包括
查询
变异
类型上的字段。使用
buildSchema
的示例通过依赖GraphQL的默认解析器行为并传入
root
值来解决此问题

默认情况下,如果字段没有指定
resolve
函数,GraphQL将检查父值(由父字段的解析器返回),并且(假设它是一个对象)将尝试在该父值上查找与字段名称匹配的属性。如果找到匹配项,则将字段解析为该值。如果匹配恰好是一个函数,它将首先调用该函数,然后解析为该函数返回的值

在上面的示例中,第一个架构中的
hello
字段没有解析器。GraphQL查看父值,对于根级别字段,父值是传入的根值。根值有一个名为
hello
的字段,它是一个函数,因此它调用该函数,然后解析为该函数返回的值。只需将
hello
属性设置为字符串而不是函数,就可以实现相同的效果

鉴于上述情况,问题中的两个例子实际上是不同的。相反,我们必须像这样修改第二个模式,使其等效:

const schema = new GraphQLSchema({
  query: new GraphQLObjectType({
    name: 'Query',
    fields: () => ({
      hello: {
        type: GraphQLString,
      }
    })
  })
});

const root = { hello: () => 'Hello world!' };

graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});
虽然通过根传递解析器是一个巧妙的技巧,但它同样只适用于根级别的字段(如
查询
变异
订阅
类型上的字段)。如果要为不同类型的字段提供解析程序,则无法使用
buildSchema
实现

底线:不要使用
buildSchema

但我想使用SDL

你仍然可以!但是不要使用香草GraphQL.js。相反,如果您想利用SDL生成模式,您应该使用
graphql工具
makeExecutableSchema
,或者使用更完整的解决方案,如
apollo server
,它在引擎盖下使用
makeExecutableSchema
makeExecutableSchema
允许您使用SDL定义模式,同时还提供一个单独的
解析器
对象。因此,您可以:

const typeDefs = `
  type Query {
    hello: String
  }
`

const resolvers = {
  Query: {
    hello: () => 'Hello!',
  },
}

const schema = makeExecutableSchema({ typeDefs, resolvers })
不同之处在于,与
buildSchema
不同,您还可以为其他类型提供解析器,甚至可以为接口或联合提供
resolveType
属性

const resolvers = {
  Query: {
    animals: () => getAnimalsFromDB(),
  }
  Animal: {
    __resolveType: (obj) => obj.constructor.name
  },
  Cat: {
    owner: (cat) => getOwnerFromDB(cat.ownerId),
  }
}
使用
makeExecutableSchema
,您还可以实现自定义标量和模式指令,轻松自定义各种模式验证规则,甚至允许实现类型从其接口继承解析器。虽然理解GraphQL.js的基础知识以及如何使用
GraphQLSchema
构造函数生成基本模式非常重要,
makeExecutableSchema
是一个更完整、更灵活的解决方案,应该是大多数项目的首选。更多细节

更新
如果您热衷于使用
buildSchema
,那么实际上可以通过使用ES6类来解决无法为非根类型提供解析器的问题。退房这并没有解决
buildSchema
的所有其他限制,但它确实使它更容易接受。

函数采用SDL(模式定义语言)中的模式,并返回
GraphQLSchema
对象。给定使用每个方法生成的两个相同的模式,运行时性能将是相同的。使用
buildSchema
的服务器的启动时间会慢一些,因为解析SDL会增加一个额外的步骤,而这在其他情况下是不存在的——是否会有明显的区别,我不能确定地说

使用
buildSchema
通常在