GraphQL Relay连接内包含列表节点报错,求解决方法
问题场景
我定义了如下GraphQL Schema:
type SectionItem = { a: String } type SectionRowConnection { pageInfo: PageInfo! edges: [SectionRowEdge] } type SectionRowEdge { node: [SectionItem] cursor: String! }
手动执行查询时一切正常:
query { sectionRows(type:someType){ edges{ node{ a } } } }
但在客户端用Relay构建查询时,却抛出了错误:
ERROR: Encountered 1 error(s): - @connection used on invalid field sectionRows . Expected the field type SectionRowConnection to have an edges { node } field that returns an object, interface, or union.
核心矛盾在于:Relay的连接规范要求edges.node必须是单个对象、接口或联合类型,但我想保留当前Schema里“每个节点返回一组列表”的结构,该怎么适配?
可行解决方案
方案1:用包装对象兼容Relay规范(最小改动)
这是最推荐的方案,不用改变核心业务逻辑,只是给列表加一层包装对象,让Relay能识别:
type SectionItem = { a: String } // 新增一个包装类型,用来承载原有的列表 type SectionRowNode { items: [SectionItem] } type SectionRowConnection { pageInfo: PageInfo! edges: [SectionRowEdge] } // 修改edge的node类型为包装对象 type SectionRowEdge { node: SectionRowNode! cursor: String! }
这样既满足了Relay对node是对象的要求,又保留了“每行返回一组SectionItem”的设计。客户端查询时只需要多嵌套一层items:
query { sectionRows(type:someType){ edges{ node{ items{ a } } } } }
原有的手动查询逻辑也可以轻松适配,只是调整一下字段路径而已。
方案2:客户端绕过Relay的连接校验(不改动Schema)
如果完全不想动Schema,可以试试这两种思路:
- 放弃使用Relay的
@connection指令,手动处理分页逻辑:把Relay当成普通GraphQL客户端用,自己管理cursor和分页状态,虽然没法用Relay内置的连接缓存,但能保留原Schema结构 - 在客户端获取数据后做一层转换:拿到
edges.node的列表后,直接在组件里使用,不用依赖Relay对连接类型的自动处理
方案3:修改Relay的验证规则(不推荐)
Relay的报错来自它内置的Schema验证规则,你可以自定义验证逻辑,放宽对edges.node类型的限制,允许列表类型。但这种方法需要修改Relay的核心配置,维护成本极高,还可能破坏Relay的其他内置功能,只适合极端场景。
总结
最稳妥的是方案1,既能满足Relay的规范要求,又能保留你原本的业务数据结构,改动成本最小。
内容的提问来源于stack exchange,提问作者ganjim

