如何在GraphQL查询层面移除菜单数据中的空数组?
嘿,这个需求很常见!要在GraphQL里去掉那些空的links数组,其实没法只靠修改查询语句直接实现,但结合服务端的小调整就能完美达成你的目标,下面给你两种实用方案:
方案1:调整服务端类型定义与解析器(最推荐)
首先得让GraphQL服务端明白,links字段不是必须返回的。先把你的菜单类型定义改一下,把links字段设为可选(不要加!):
type MenuItem { label: String! url: String! links: [MenuItem] # 这里没有强制非空,意味着字段可以为null或不出现 } type Query { menu: [MenuItem]! }
接下来在links字段的解析器里加个判断:如果子链接数组是空的,就返回null而不是空数组。用JavaScript写的解析器示例大概是这样:
const resolvers = { MenuItem: { links: (parent) => { // 当子链接为空时返回null,否则返回原数组 return parent.links.length > 0 ? parent.links : null; } }, // 其他查询/字段的解析逻辑... };
这样调整后,你再执行原来的查询语句,GraphQL会自动忽略值为null的links字段,返回的结果就和你想要的完全一致啦。
方案2:用自定义指令(适合没法改核心解析器的场景)
如果没法直接修改服务端的基础解析器,可以写个自定义指令(比如@removeEmptyArray),让服务端在返回字段前检查是不是空数组,是的话就移除它。
以Apollo Server为例,自定义指令的实现大概是这样:
import { GraphQLDirective, DirectiveLocation } from 'graphql'; import { SchemaDirectiveVisitor, defaultFieldResolver } from '@apollo/server'; // 定义指令 const removeEmptyArrayDirective = new GraphQLDirective({ name: 'removeEmptyArray', locations: [DirectiveLocation.FIELD], }); // 实现指令的访问器逻辑 class RemoveEmptyArrayDirective extends SchemaDirectiveVisitor { visitFieldDefinition(field) { const originalResolve = field.resolve || defaultFieldResolver; field.resolve = async function (...args) { const result = await originalResolve.apply(this, args); // 空数组就返回null,让GraphQL自动忽略该字段 return Array.isArray(result) && result.length === 0 ? null : result; }; } }
之后在你的查询里给links字段加上这个指令就行:
{ menu { label url links @removeEmptyArray { label url links @removeEmptyArray { label url } } } }
为啥纯查询语句搞不定?
这里得说清楚:GraphQL的查询是静态声明的——你明确请求了links字段,服务端就会返回它,不管值是空数组还是null。要动态移除字段,必须让服务端在解析时判断值的内容,所以得配合上面的两种方案才行。
内容的提问来源于stack exchange,提问作者Joe Lloyd
相关产品推荐
相关产品推荐

