Apollo GraphQL resolver未执行 查询返回null异常排查
Apollo GraphQL resolver未执行、返回null问题修复
问题现象
开发过程中出现以下异常:
- 执行
taskResults查询时,接口返回taskResults: null,预期返回空数组[] - 控制台未打印resolver内预设的
taskResults日志,对应解析函数未被触发
问题相关代码
服务初始化代码:
import { ApolloServer } from 'apollo-server'; import path from 'path'; import { loadSchemaSync } from '@graphql-tools/load' import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader' ... const schema = loadSchemaSync(path.join(__dirname, './schema/*.graphql'), { loaders: [ new GraphQLFileLoader() ] }) const resolvers = { Query: { taskResults: (root, args, context) => { console.log('taskResults') return [] } } } ;(async () => { const server = new ApolloServer({ schema, resolvers, csrfPrevention: true }); const { url } = await server.listen() console.log(`🚀 Server ready at ${url}`); })().catch(console.error)
执行的查询语句:
query { taskResults { id } }
实际返回结果:
{ "data": { "taskResults": null } }
预期返回结果:
{ "data": { "taskResults": [] } }
根因分析
当向ApolloServer构造函数传入schema配置项时,服务会直接使用传入的现成GraphQLSchema实例,自动忽略同配置中传入的resolvers、typeDefs字段。
通过loadSchemaSync从.graphql文件加载得到的schema仅包含类型定义,没有挂载任何resolver逻辑。服务启动后找不到taskResults字段对应的解析函数,就按照GraphQL默认规则返回null,自然不会执行定义的resolver、也不会打印日志。
修复方案
两种方案任选其一即可:
方案1:手动合并生成可执行schema
使用@graphql-tools/schema的makeExecutableSchema方法,把加载到的类型定义和resolvers合并为完整的可执行schema后再传入服务。
- 安装依赖
npm install @graphql-tools/schema
- 修改服务初始化代码
import { ApolloServer } from 'apollo-server'; import path from 'path'; import { loadSchemaSync } from '@graphql-tools/load' import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader' import { makeExecutableSchema } from '@graphql-tools/schema' // 加载纯类型定义 const typeDefs = loadSchemaSync(path.join(__dirname, './schema/*.graphql'), { loaders: [ new GraphQLFileLoader() ] }) const resolvers = { Query: { taskResults: (root, args, context) => { console.log('taskResults') return [] } } } // 合并为带resolver的可执行schema const schema = makeExecutableSchema({ typeDefs, resolvers }) ;(async () => { const server = new ApolloServer({ schema, csrfPrevention: true }); const { url } = await server.listen() console.log(`🚀 Server ready at ${url}`); })().catch(console.error)
方案2:直接传入typeDefs和resolvers,跳过手动构造schema
ApolloServer内部会自动将传入的typeDefs和resolvers组装为可执行schema,无需提前手动加载构造schema实例:
import { ApolloServer } from 'apollo-server'; import path from 'path'; import { loadSchemaSync } from '@graphql-tools/load' import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader' // 加载得到的类型定义直接传给typeDefs字段 const typeDefs = loadSchemaSync(path.join(__dirname, './schema/*.graphql'), { loaders: [ new GraphQLFileLoader() ] }) const resolvers = { Query: { taskResults: (root, args, context) => { console.log('taskResults') return [] } } } ;(async () => { const server = new ApolloServer({ typeDefs, resolvers, csrfPrevention: true }); const { url } = await server.listen() console.log(`🚀 Server ready at ${url}`); })().catch(console.error)
内容的提问来源于stack exchange,提问作者mitchkman
相关产品推荐
相关产品推荐

