You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ruby的GraphQL Union类型中使用列表?

在GraphQL Ruby中为Union类型添加列表成员的问题

背景

GraphQL Ruby文档中介绍了Union类型的定义方式:

class Types::CommentSubject < Types::BaseUnion
  description "Objects which may be commented on"
  possible_types Types::Post, Types::Image

  # 可选:定义此方法会覆盖`Schema.resolve_type`
  def self.resolve_type(object, context)
    if object.is_a?(BlogPost)
      Types::Post
    else
      Types::Image
    end
  end
end

同时也说明了如何声明列表类型的字段:

# 返回列表类型的字段:
# 等同于上方的`aliases: [String!]`
field :aliases, [String]

# 接受列表类型的参数:
argument :categories, [Types::PostCategory], required: false

但找不到如何将列表作为Union的可选成员类型的实现方法。

尝试的代码及问题

我编写了如下Union类型定义:

class Types::ArgumentValueType < Types::BaseUnion
  possible_types GraphQL::Types::String, GraphQL::Types::Boolean, GraphQL::Types::Int

  def self.resolve_type(object, _context)
    if object.is_a?(String)
      GraphQL::Types::String
    elsif object.is_a?(Array)
      [GraphQL::Types::String]
    elsif object.is_a?(FalseClass)
      GraphQL::Types::Boolean
    elsif object.is_a?(TrueClass)
      GraphQL::Types::Boolean
    elsif object.is_a?(Integer)
      GraphQL::Types::Int
    end
  end
end

这段代码能勉强运行,但当对象是数组时,返回的value字段会被序列化为字符串:

{
  "name": "top_box",
  "type": "Array",
  "description": "The chosen values of the scale which should be combined",
  "position": 2,
  "optional": false,
  "value": "[\"8\", \"9\", \"10\"]"
}

我期望的是直接返回字符串数组:

{
  "name": "top_box",
  "type": "Array",
  "description": "The chosen values of the scale which should be combined",
  "position": 2,
  "optional": false,
  "value": [
    "8",
    "9",
    "10"
  ]
}

仅在一个关于“GraphQL Union嵌套Union”的回答评论中看到,这种需求可能无法实现。

尝试其他方法的错误信息

  • 把[GraphQL::Types::String]加入possible_types时,报错:
undefined method `graphql_name' for [GraphQL::Types::String]:Array
  • 把GraphQL::Schema::List.new(GraphQL::Types::String)加入possible_types时,报错:
undefined method `directives' for #<GraphQL::Schema::List:0x000000010f690950 @of_type=GraphQL::Types::String>
  • 在elsif object.is_a?(Array)分支里把[GraphQL::Types::String]替换为GraphQL::Schema::List.new(GraphQL::Types::String)时,报错:
.resolve_type should return a type definition, but got #<GraphQL::Schema::List:0x000000010f9fd6b0
@of_type=GraphQL::Types::String> (GraphQL::Schema::List) from `resolve_type(Types::ArgumentValueType,
["8", "9", "10"], #<GraphQL::Query::Context:0x000000010f8ed018>)`

现有解决方案(带嵌套)

我通过添加包装类实现了需求,但会多一层嵌套:

# frozen_string_literal: true

module Types
  class ListOfStringsType < Types::BaseObject
    field :values, [String]
  end
end

查询语句:

arguments {
  name
  type
  description
  position
  optional
  value {
    ... on ListOfStrings {
      values
    }
  }
}

返回结果:

"arguments": [
  {
    "name": "top_box",
    "type": "Array",
    "description": "The chosen values of the scale which should be combined",
    "position": 2,
    "optional": false,
    "value": {
      "values": [
        "8",
        "9",
        "10"
      ]
    }
  },
  {
    "name": "measure",
    "type": "Measure",
    "description": "The name of the measure to be \"top-boxed\"",
    "position": 1,
    "optional": false,
    "value": "unique_and_different"
  }
]

我希望能避免这个额外的嵌套层级。


内容的提问来源于stack exchange,提问作者Beetle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 08:05:21