Search code examples
graphqlgraphql-ruby

How to handle a field that could return one of several scalar types in graphql


In graphql (using the excellent graphql-ruby gem), I'm trying to return an object with a field that can equal either a Boolean, Integer, or String. My initial thought was to return a union of Boolean, Integer, or String, but graphql-ruby informed me that unions cannot contain scalar types (I imagine this is constraint imposed by the spec, rather than graphql-ruby).

The solution I can think of (not great) is to return the value as a json string and parse it on the client side. Is there a better way to handle a return value that could be one of several scalars?

Thanks!


Solution

  • I've been able to accomplish this by creating a graphql custom scalar type which simply checks to make sure the value is either a Boolean, Integer, or String and, if so, returns that value unchanged. Otherwise, an error is returned. This solution does not require any additional parsing on the client side.

    In graphql-ruby, the implementation looks like

    GraphScalar::AnyPrimative = GraphQL::ScalarType.define do
      name "AnyPrimativeScalar"
    
      coerce_input ->(value, ctx) { 
        case value
        when String, TrueClass, FalseClass, Integer, Float then value
        else
          GraphQL::ExecutionError.new("Invalid value type: #{value.class.name}")
        end
      }
    
      coerce_result ->(value, ctx) { 
        case value
        when String, TrueClass, FalseClass, Integer, Float then value
        else
          GraphQL::ExecutionError.new("Invalid value type: #{value.class.name}")
        end
      }
    end
    

    note: this implementation actually allows for floats as well