如何在GraphQL外部利用GraphQL-ruby定义的类型格式化数据?
直接用GraphQL类型格式化数据(无需执行内部查询)
针对你使用GraphQL-Ruby的场景,完全可以直接通过实例化已定义的GraphQL类型、模拟字段解析逻辑来格式化数据,不用执行内部GraphQL查询。以下是具体实现方案:
1. 正确初始化GraphQL类型对象
GraphQL-Ruby的BaseObject(即你的Types::BaseObject)支持通过initialize方法传入数据源object和GraphQL上下文context,注意context必须是GraphQL::Query::Context实例,不能用普通哈希:
# 构建合法的GraphQL上下文 context = GraphQL::Query::Context.new(values: { "id_suffix" => "foo" }) # 初始化UserType实例,传入数据源和上下文 typed_object = Types::UserType.new(object: User.find(1), context: context)
此时直接调用类型中定义的字段方法(比如custom_id)就能得到解析后的值:
typed_object.custom_id # => "1foo"
2. 实现to_h方法批量格式化所有字段
要一次性把所有字段转成哈希,可以给基础类型添加一个通用的序列化模块,模拟GraphQL解析所有字段的逻辑:
# 定义通用序列化模块 module TypeSerializable def to_h self.class.fields.each_with_object({}) do |(field_name, field_def), hash| value = resolve_field(field_def) # 嵌套类型递归转哈希(如果嵌套类型也包含该模块) hash[field_name] = value.respond_to?(:to_h) ? value.to_h : value end end private def resolve_field(field_def) # 优先调用类型中自定义的字段方法(比如你的custom_id) if respond_to?(field_def.name) public_send(field_def.name) else # 无自定义方法时,直接取数据源object的对应属性 object.public_send(field_def.name) end end end # 在你的基础类型中引入该模块 class Types::BaseObject < GraphQL::Schema::Object include TypeSerializable end
现在你就能直接调用to_h得到格式化后的哈希:
typed_object.to_h # => { "id" => 1, "custom_id" => "1foo" }
说明
- 这个方案完全模拟了GraphQL解析字段的逻辑:优先使用类型中定义的实例方法作为字段解析器,没有自定义方法时直接映射数据源的属性。
- 如果有嵌套的GraphQL类型(比如UserType包含AddressType字段),只要嵌套类型也继承了包含
TypeSerializable的BaseObject,to_h会自动递归处理嵌套字段。
内容的提问来源于stack exchange,提问作者nekogami
相关产品推荐
相关产品推荐

