Absinthe联合类型解析器向对象字段解析器传入空映射问题
解决Absinthe联合类型子解析器获取空映射的问题
我刚仔细看了你的代码,发现问题出在Absinthe处理联合类型的工作流程上——你在resolve_type里能拿到完整数据,但子对象解析器拿到空映射,是因为两者接收的数据来源不一样。
问题到底出在哪?
Absinthe处理联合类型的步骤是这样的:
- 先解析父字段(也就是
:contact里的:info),拿到这个字段对应的数据列表; - 对列表里的每一项数据,调用
resolve_type判断它属于:foo还是:bar; - 最后,子对象(
:foo/:bar)的解析器会接收当前这一项的数据作为第一个参数。
你的代码里,:contact的:info字段没有自定义resolve函数,Absinthe会默认从父contact对象里读取:info字段的值。如果这个值是空的,子解析器自然就拿到%{}了。而你在resolve_type里能拿到数据,大概率是父字段其实有返回数据,但没有正确传递给子类型——这是因为你没给:info字段写正确的resolve逻辑。
怎么修复?
按照下面的步骤调整代码就行:
1. 给:contact的:info字段添加resolve函数
首先要确保:info字段返回的是包含每个子项完整数据的列表,比如模拟数据源的话可以这么写:
object :contact do field :info, list_of(:info) do resolve(fn _contact, _, _ -> # 这里替换成你实际获取数据的逻辑,比如从数据库查询 info_items = [ %{"info" => "foo", "phone" => "13800138000"}, %{"info" => "bar", "id" => "bar_001"} ] {:ok, info_items} end) end end
2. 调整子对象的解析逻辑
子对象的解析器第一个参数就是当前项的数据,直接从里面取字段就行:
object :foo do field :phone, non_null(:string), resolve: fn foo_data, _, _ -> IO.inspect(foo_data) # 现在会拿到%{"info" => "foo", "phone" => "13800138000"} {:ok, foo_data["phone"] || "hardcodedfornow"} end end object :bar do field :id, non_null(:string), resolve: fn bar_data, _, _ -> IO.inspect(bar_data) # 现在会拿到%{"info" => "bar", "id" => "bar_001"} {:ok, bar_data["id"] || "hardcodedfornow"} end end
3. 完善resolve_type的默认分支
建议给resolve_type加个默认分支,处理未知类型的情况:
union :info do description("Union type representing foo or bar info") types([:foo, :bar]) resolve_type(fn %{"info" => "foo"}, _ -> :foo %{"info" => "bar"}, _ -> :bar _, _ -> nil # 未知类型返回nil,Absinthe会抛出友好错误 end) end
核心逻辑再强调下
- 父字段的
resolve是负责拿数据的源头,必须返回正确的子项列表; resolve_type只是做类型判断,不会修改或传递数据;- 子对象解析器接收的是单个子项的数据,不是父字段的整体数据。
这样调整后,你应该就能看到子解析器拿到正确的数据,而不是空映射了。
内容的提问来源于stack exchange,提问作者Raphael Rafatpanah
相关产品推荐
相关产品推荐

