buildSchema 函数采用 SDL(模式定义语言)中的模式并返回一个 GraphQLSchema 对象。给定每个方法生成的两个相同模式,运行时性能将是相同的。使用 buildSchema 的服务器的启动时间会更慢,因为解析 SDL 会增加一个额外的步骤,否则会不存在 - 是否会有明显差异,我无法确定。
通常不建议使用buildSchema,因为它会严重限制架构的功能。
使用buildSchema 生成的架构:
- 无法为单个字段指定解析函数
- 无法为类型指定
resolveType 或isTypeOf 属性,导致无法使用Unions 和Interfaces
- 无法使用自定义标量
第 1 项强调不够——buildSchema 不允许您为架构中的任何字段指定解析器函数。这包括您的 Query 和 Mutation 类型上的字段。使用 buildSchema 的示例通过依赖 GraphQL 的默认解析器行为并传入 root 值来解决此问题。
默认情况下,如果一个字段没有指定 resolve 函数,GraphQL 将检查父值(由父字段的解析器返回)并且(假设它是一个对象)将尝试在该父项上查找一个属性与字段名称匹配的值。如果找到匹配项,则将字段解析为该值。如果匹配恰好是一个函数,它首先调用该函数,然后解析为该函数返回的值。
在上面的示例中,第一个模式中的 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);
});
虽然通过根传递解析器是一个巧妙的技巧,但它仅适用于根级字段(如 Query、Mutation 或 Subscription 类型上的字段)。如果您想为不同类型的字段提供解析器,则无法使用buildSchema。
底线:不要使用buildSchema。
但我想使用 SDL!
你仍然可以! 但是...不要使用普通的 GraphQL.js。相反,如果您想利用 SDL 生成架构,您应该改用 graphql-tools' makeExecutableSchema 或使用更完整的解决方案,如 apollo-server,它在后台使用 makeExecutableSchema。 makeExecutableSchema 允许您使用 SDL 定义模式,同时还提供单独的 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),
}
}
使用makeExecutableSchema,您还可以实现自定义标量和模式指令,轻松自定义各种模式验证规则,甚至允许实现类型从其接口继承解析器。虽然了解 GraphQL.js 的基础知识以及如何使用GraphQLSchema 构造函数生成基本模式至关重要,但makeExecutableSchema 是一个更完整、更灵活的解决方案,应该是大多数项目的首选。 See the docs 了解更多详情。
更新
如果您一心想要使用buildSchema,实际上可以通过使用 ES6 类来解决无法为非根类型提供解析器的问题。查看this sample schema。这并没有解决buildSchema 的所有其他限制,但它确实使它更可口。