Apollo Server数组单个元素无效时能否返回部分成功结果?
问题根因
你遇到的是GraphQL标准的空值冒泡规则导致的问题:
当标记为!的非空字段返回null时,空值会向上冒泡到最近的父节点:
- 你的原Schema定义大概率如下:
type Customer { id: ID! name: String! email: String! } type Query { # 数组本身非空,且数组内的每一个Customer元素也要求非空 customers: [Customer!]! }
- 当某条Customer的email(非空字段)实际返回null时,会先将当前Customer对象置为null;又因为数组元素要求
Customer!非空,空值会继续向上冒泡到整个customers数组,最终返回全量null,就是你看到的错误结果。
解决方案
完全可以实现保留有效数据+返回对应错误的需求,不需要你手动提前校验全量复杂数据,有两种成熟的实现方式:
方案1:调整Schema+字段级Resolver处理(推荐,符合GraphQL规范)
步骤1:修改数组元素为可空
将customers返回类型调整为[Customer]!,允许数组内存在单个null元素,阻断空值向上冒泡到整个数组:
type Query { customers: [Customer]! # 数组本身非空,元素允许为null }
步骤2:为可能缺失的非空字段添加单独Resolver
不需要校验全量数据,只需要给Customer.email这类可能缺数的字段写独立Resolver,检测到空值时抛出错误即可,Apollo Server会自动将错误收集到返回体的errors数组中:
const resolvers = { Customer: { email: (parent) => { if (!parent.email) { // 抛出的错误会被自动收集,同时触发单条Customer置为null throw new Error(`id为${parent.id}的客户email字段缺失`); } return parent.email; } }, Query: { customers: () => { // 直接返回数据源拿到的原始数组即可,无需提前校验 return getCustomersFromDB(); } } }
最终返回效果
{ "data": { "customers": [ {"id": "1", "name": "张三", "email": "zhangsan@test.com"}, null, // 仅错误的单条记录被置为null {"id": "3", "name": "李四", "email": "lisi@test.com"} ] }, "errors": [{ "message": "id为2的客户email字段缺失", "path": ["customers", 1, "email"] // 明确标注错误的具体位置 }] }
UI侧只需过滤掉数组中的null值即可正常渲染所有有效数据,也可以根据errors字段做对应提示。
小提示:如果不想出现null的数组元素,也可以在Resolver中给缺失的字段返回合法默认值(比如email返回空字符串
""),这样连单条记录都不会变为null,同时仍然可以抛出错误到errors数组。
方案2:自定义Apollo插件拦截空值冒泡
如果你的业务Schema已经固定不能修改,可以自定义Apollo Server插件,在空值冒泡到数组层之前进行拦截,只将有问题的单条记录置为null,不需要调整Schema定义,适合存量项目使用。
内容的提问来源于stack exchange,提问作者Cam Jackson
相关产品推荐
相关产品推荐

