如何让GraphQL分页查询返回含错误的部分响应?
问题
我编写了如下GraphQL查询:
query { heroes { node { name } endCursor } }
我想实现GraphQL返回部分响应(某个英雄出错时不影响其他英雄和endCursor),编写了如下解析器:
{ Query: { heroes: async (_) => { const heroesData = await loadHeroesFromDataWarehouse(); return { endCursor: heroesData.endCursor; node: heroesData.map(h => h.name === 'hulk' ? new ApolloError('Hulk is too powerful') : h) } } } }
我期望的响应是:
{ "errors": [ { "message": "Hulk is too powerful", "path": [ "heroes", "node", "1" ] } ], "data": { "heroes": { "node": [ { "name": "spiderman" }, null, { "name": "ironman" } ], "endCursor": "xxx" } } }
但实际响应中整个heroes字段变为null:
{ "errors": [ { "message": "Hulk is too powerful", "path": [ "heroes" ] } ], "data": { "heroes": null } }
请问如何调整解析器以得到预期的部分响应?
解决方案
问题出在你直接在heroes顶层解析器里返回了包含ApolloError对象的数组。GraphQL会将父解析器返回的错误对象判定为整个字段解析失败,因此把heroes设为null。要实现部分响应,需要在子字段的解析器中抛出错误,而非在父解析器中返回错误对象。
调整步骤如下:
- 拆分解析逻辑:给
Hero类型(即node数组的元素类型)的字段单独编写解析器,在子字段层面抛出错误。 - 修正语法错误:原解析器中
endCursor后的分号要改成逗号。
调整后的解析器示例:
{ Query: { heroes: async (_) => { const heroesData = await loadHeroesFromDataWarehouse(); // 仅返回原始数据,不在此层处理错误 return { endCursor: heroesData.endCursor, node: heroesData.nodes }; } }, // 给Hero类型的name字段编写解析器 Hero: { name: (parent) => { if (parent.name === 'hulk') { throw new ApolloError('Hulk is too powerful'); } return parent.name; } } }
原理说明
GraphQL的错误处理是字段级别的:当某个子字段解析时抛出错误,GraphQL会将该子字段(或对应的数组元素)设为null,同时保留其他正常解析的字段和数据。而如果在父字段的解析器中直接返回错误对象,会被视为整个父字段解析失败,导致父字段变为null。
这样调整后,当遇到name为hulk的英雄时,只会把该英雄对应的数组元素设为null,endCursor和其他英雄的数据都会正常返回,同时错误信息的path会指向具体出错的位置。
内容的提问来源于stack exchange,提问作者zgrw
相关产品推荐
相关产品推荐

