GraphQL添加Material类型报错:fields需为对象或返回对象的函数
问题描述
我开发了一个基于MongoDB的应用,原本Customer和Ticket相关Schema运行正常。添加Materials集合并配置Schema后,持续报错:
Error: Material fields must be an object with field names as keys or a function which returns such an object
服务器崩溃,无法访问http://localhost:5400/graphql,注释Materials相关代码后恢复正常。以下是我的Schema代码:
const Customer = require('../models/Customer'); const Ticket = require('../models/Ticket'); const Material = require('../models/Material'); const { GraphQLObjectType, GraphQLString, GraphQLSchema, GraphQLID, GraphQLList, GraphQLInt, GraphQLNonNull, GraphQLDeprecatedDirective, } = require('graphql'); //Tickets const TicketType = new GraphQLObjectType({ name: 'Ticket', fields: () => ({ id: { type: GraphQLID }, date: { type: GraphQLString}, ticketNum: { type: GraphQLString}, customer: { type: CustomerType, resolve(parent, args) { return Customer.findById(parent.customerId); }, }, material: { type: GraphQLString}, tareWeight: { type: GraphQLInt}, grossWeight: { type: GraphQLInt}, netWeight: { type: GraphQLInt}, notes: { type: GraphQLString}, }), }); //Materials const MaterialType = new GraphQLObjectType({ name: "Material", Fields: () => ({ id: { type: GraphQLID }, matId: { type: GraphQLString}, name: { type: GraphQLString }, price: { type: GraphQLInt }, unit: { type: GraphQLString}, notes: { type: GraphQLString,} }), }); //Customers const CustomerType = new GraphQLObjectType({ name: "Customer", fields: () => ({ id: { type: GraphQLID }, custId: { type: GraphQLString}, name: { type: GraphQLString}, street: { type: GraphQLString}, city: { type: GraphQLString}, zip: { type: GraphQLString}, webSite: { type: GraphQLString}, email: { type: GraphQLString}, phone: { type: GraphQLString}, }), }); const RootQuery = new GraphQLObjectType({ name: 'RootQueryType', fields: { tickets: { type: new GraphQLList(TicketType), resolve(parent, args) { return Ticket.find(); }, }, ticket: { type: TicketType, args: { id: { type: GraphQLID } }, resolve(parent, args) { return Ticket.findById(args.id); }, }, customers: { type: new GraphQLList(CustomerType), resolve(parent, args) { return Customer.find(); }, }, customer: { type: CustomerType, args: { id: { type: GraphQLID } }, resolve(parent, args) { return Customer.findById(args.id); }, }, materials: { type: new GraphQLList(MaterialType), resolve(parent, args) { return Material.find(); }, }, material: { type: MaterialType, args: {id: { type: GraphQLID } }, resolve(parent, args) { return Material.findById(args.id); }, }, }, }); //Mutations const mutation = new GraphQLObjectType({ name: 'Mutation', fields: { //Add Customer addCustomer: { type: CustomerType, args: { custId: { type: GraphQLString}, name: { type: GraphQLString}, street: { type: GraphQLString}, city: { type: GraphQLString}, zip: { type: GraphQLString}, webSite: { type: GraphQLString}, email: { type: GraphQLString}, phone: { type: GraphQLString}, }, resolve(parent, args) { const customer = new Customer({ custId: args.custId, name: args.name, street: args.street, city: args.city, zip: args.zip, webSite: args.webSite, email: args.email, phone: args.phone, }); return customer.save(); } }, // //Add Material addMaterial: { type: MaterialType, args: { matId: { type: GraphQLString}, name: { type: GraphQLString}, price: { type: GraphQLString}, unit: { type: GraphQLString}, notes: { type: GraphQLString}, }, resolve(parent, args) { const material = new Material({ matId: args.matId, name: args.name, price: args.price, unit: args.unit, notes: args.notes, }); return material.save(); } }, // Delete Customer deleteCustomer: { type: CustomerType, args: { id: { type: GraphQLNonNull(GraphQLID) }, }, resolve(parent, args) { return Customer.findByIdAndRemove(args.id); }, }, // Add Ticket addTicket: { type: TicketType, args: { date: { type: GraphQLNonNull(GraphQLString) }, ticketNum: { type: GraphQLNonNull(GraphQLString) }, customerId: { type: GraphQLNonNull(GraphQLID) }, material: { type: GraphQLNonNull(GraphQLString) }, tareWeight: { type: GraphQLNonNull(GraphQLInt) }, grossWeight: { type: GraphQLNonNull(GraphQLInt) }, netWeight: { type: GraphQLNonNull(GraphQLInt) }, notes: { type: GraphQLNonNull(GraphQLString) }, }, resolve(parent, args) { const ticket = new Ticket({ date: args.date, ticketNum: args.ticketNum, customerId: args.customerId, material: args.material, tareWeight: args.tareWeight, grossWeight: args.grossWeight, netWeight: args.netWeight, notes: args.notes, }); return ticket.save(); } }, //Delete a Ticket deleteTicket: { type: TicketType, args: { id: { type: GraphQLNonNull(GraphQLID) }, }, resolve(parent, args) { return Ticket.findByIdAndRemove(args.id); }, }, // Update Ticket updateTicket: { type: TicketType, args: { id: { type: GraphQLNonNull(GraphQLID) }, date: { type: GraphQLString }, ticketNum: { type: GraphQLString }, // customerId: { type: GraphQLID }, material: { type: GraphQLString }, tareWeight: { type: GraphQLInt }, grossWeight: { type: GraphQLInt }, netWeight: { type: GraphQLInt }, notes: { type: GraphQLString }, }, resolve(parent, args) { return Ticket.findByIdAndUpdate( args.id, { $set: { date: args.date, ticketNum: args.ticketNum, // customerId: args.customerId, material: args.material, tareWeight: args.tareWeight, grossWeight: args.grossWeight, netWeight: args.netWeight, notes: args.notes, }, }, { new: true } ); }, }, }, }); module.exports = new GraphQLSchema({ query: RootQuery, mutation });
错误原因
定义MaterialType时出现大小写错误:把必填属性fields写成了Fields(首字母大写)。GraphQL无法识别这个错误的属性名,会直接忽略它,导致MaterialType缺少核心的字段配置,从而抛出报错。
修复方案
- 修正
MaterialType中的属性名,将Fields改为小写的fields,和其他类型保持一致:
//Materials const MaterialType = new GraphQLObjectType({ name: "Material", fields: () => ({ // 此处修正为小写fields id: { type: GraphQLID }, matId: { type: GraphQLString}, name: { type: GraphQLString }, price: { type: GraphQLInt }, unit: { type: GraphQLString}, notes: { type: GraphQLString,} }), });
- 额外修正一个类型不匹配问题:
addMaterialmutation中price的类型是GraphQLString,但MaterialType里price定义为GraphQLInt,统一类型避免后续数据异常:
//Add Material addMaterial: { type: MaterialType, args: { matId: { type: GraphQLString}, name: { type: GraphQLString}, price: { type: GraphQLInt }, // 此处修正为GraphQLInt unit: { type: GraphQLString}, notes: { type: GraphQLString}, }, resolve(parent, args) { const material = new Material({ matId: args.matId, name: args.name, price: args.price, unit: args.unit, notes: args.notes, }); return material.save(); } },
内容的提问来源于stack exchange,提问作者Nate
相关产品推荐
相关产品推荐

