buildSchema和GraphQLSchema之间的显着差异?

时间:2018-12-31 06:00:25

标签: graphql graphql-js

两者之间有显着差异吗?我对从运行时和启动性能到功能和工作流程差异的任何事物都感兴趣。文档在解释这种差异以及何时应该使用另一种之上时做得很差。

两个版本中的示例:

buildSchema

ArithmeticException

GraphQLSchema

const { graphql, buildSchema } = require('graphql');

const schema = buildSchema(`
  type Query {
    hello: String
  }
`);

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

graphql(schema, '{ hello }', root).then((response) => {
  console.log(response);
});

1 个答案:

答案 0 :(得分:8)

buildSchema函数采用SDL(模式定义语言)的架构,并返回GraphQLSchema对象。给定每种方法生成的两个相同的架构,运行时性能将相同。使用buildSchema的服务器的启动时间会更慢,因为解析SDL会增加一个否则不存在的额外步骤-无论是否存在值得注意的差异,我无法确切地说

通常不建议使用buildSchema,因为它会严重限制架构的功能。

使用buildSchema生成的架构:

  • 无法为单个字段指定解析功能
  • 无法为类型指定resolveTypeisTypeOf属性,因此无法使用UnionsInterfaces
  • 无法使用自定义标量

项目#1承受的压力不足-buildSchema不允许您为架构中的任何字段指定解析器功能。这包括您的QueryMutation类型的字段。使用buildSchema的示例通过依赖GraphQL的默认解析器行为并传递一个root值来解决此问题。

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

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

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

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);
});

虽然通过根传递解析器是一个巧妙的技巧,但它再次仅适用于根级别字段(例如QueryMutationSubscription类型的字段)。如果您想为其他类型的字段提供解析器,则无法使用buildSchema

底线:请勿使用buildSchema

但是我想使用SDL!

您仍然可以! 但是 ...不要使用香草GraphQL.js做到这一点。相反,如果要利用SDL生成模式,则应该使用graphql-tools'makeExecutableSchema或使用更完整的解决方案,例如apollo-server,该解决方案在引擎盖。 makeExecutableSchema允许您使用SDL定义架构,同时还提供单独的makeExecutableSchema对象。因此,您可以这样做:

resolvers

区别在于,与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), } } ,您还可以实现自定义标量和模式指令,轻松自定义各种模式验证规则,甚至允许实现类型从其接口继承解析器。尽管了解GraphQL.js的基础知识以及如何使用makeExecutableSchema构造函数生成基本架构非常重要,但GraphQLSchema是一个更完整,更灵活的解决方案,应该是大多数项目的首选。 See the docs了解更多详情。