如何在GraphQL Pothos中创建自定义JSONObject标量类型?
问题描述
尝试创建自定义标量JSONObject用于接收JSON格式的文档数组作为mutation的输入参数,但无法正常工作。该标量已显示在GraphiQL界面中,但系统始终提示字段需为定义的JSONObject类型。尝试过使用预定义的JSONResolver以及两种自定义标量实现,问题依旧。需要接收的输入格式为:
[{ "weight": 0, "spotsAvailable": [{ "userId": "empty", "name": "empty" }, { "userId": "67fd6sdhfds7yf87", "name": "John" }] }, { "weight": 0, "spotsAvailable": [{ "userId": "empty", "name": "empty" }, { "userId": "67fd6sdhfds7yf87", "name": "John" }] }]
解决方案
1. 修正自定义标量的解析逻辑
现有自定义标量存在两处关键问题:
- 首个实现强制要求输入包含
_id字段,与需求的数组格式冲突 - 两个实现均缺失
parseLiteral方法,GraphQL处理查询字面量时会因此解析失败
修改后的自定义标量实现:
builder.scalarType('JSONObject', { serialize: (value) => { // 序列化时直接返回值,确保输出符合JSON格式 return value; }, parseValue: (value: any) => { // 允许对象或数组,且非空非undefined if ((typeof value === 'object' && value !== null) || Array.isArray(value)) { return value; } throw new Error('JSONObject必须是对象或数组类型'); }, // 处理GraphQL AST节点解析,必须实现 parseLiteral: (ast) => { switch (ast.kind) { case Kind.OBJECT: case Kind.LIST: return ast.value; default: throw new Error('JSONObject只能解析对象或数组类型的字面量'); } } });
2. 修复Mutation中的参数获取错误
createEvent的resolve函数中错误使用argWeights变量,实际输入参数为weights,导致值无法正确传递。修正后的代码:
resolve: (_, { input: { longitude, latitude, name, date, description, cost, link, weights } }, context) => { const location: Location = { type: 'Point', coordinates: [longitude, latitude] }; let anObject = { createdBy: context.currentUser._id as ObjectId, location, name, date, description, cost: cost ?? undefined, link: link ?? undefined, weights: weights ?? undefined }; return dbMutations.createEvent(anObject); }
3. 确认标量注册与类型定义匹配
若使用自定义标量,需移除builder.addScalarType('JSONObject', JSONResolver, {})避免冲突,保留如下类型定义即可:
Scalars: { Date: { Input: Date; Output: Date; }; mongoId: { Input: ObjectId; Output: ObjectId; }; JSONObject: { Input: any; Output: any; }; objectIdOrEmpty: { Input: ObjectId | Empty; Output: ObjectId | Empty; }; };
4. GraphiQL输入验证
测试mutation时确保weights字段为合法JSON数组,示例查询:
mutation CreateEvent($input: CreateEventInput!) { createEvent(input: $input) { _id name weights } }
变量:
{ "input": { "longitude": 120.123, "latitude": 30.456, "name": "Test Event", "date": "2024-12-31T12:00:00Z", "description": "Test Description", "weights": [ { "weight": 0, "spotsAvailable": [{ "userId": "empty", "name": "empty" }, { "userId": "67fd6sdhfds7yf87", "name": "John" }] }, { "weight": 0, "spotsAvailable": [{ "userId": "empty", "name": "empty" }, { "userId": "67fd6sdhfds7yf87", "name": "John" }] } ] } }
内容的提问来源于stack exchange,提问作者Wayne
相关产品推荐
相关产品推荐

