This is a quick post of a self-contained MiniTest example of how to implement resolve_type
on a GraphQL::Schema
if you are using graphql-ruby
without using the Ruby DSL to define your schema.
graphql-ruby
provides two ways to create a schema, one from the .graphql
file directly (from_definition
) and by using the "class based definition"
Taking a Schema Definition Language (SDL) such as GraphQL and hiding it behind a Domain Specific Language (DSL) in a higher level turing-complete language strikes me as utterly irresponsible, the value of an SDL is in the interchange format, and for us that was an absolute necessity.
Many features of graphql-ruby
behave differently, or simply don't work at all, or are undocumented if you use the SDL approach rather than their preferred DSL, we run into issues with it from time to time.
In this case, without the DSL the Gem cannot infer what type
a resolver result has, and how to resolve that using the variant types from the union. It is required to implement a resolve_type
function in your resolver tree, but where and how to do that isn't obvious, I hope this post helps:
# frozen_string_literal: true require 'test_helper' module Schema class UnionsFromDefinitionTest < Minitest::Test def definition <<~EOSCHEMA type Wimpel { id: ID! } type Doodad { code: ID! } union Widget = Doodad | Wimpel type Query { widget: [Widget]! } EOSCHEMA end def resolvers Sch3ma.default_resolvers.merge( { 'Query' => { 'widget' => lambda { |_obj, _args, _ctx| [OpenStruct.new(id: 'i am wimpel'), OpenStruct.new(code: 'i am doodad')] } }, 'resolve_type' => lambda { |_type, obj, ctx| type_name = if obj.respond_to? :id 'Wimpel' elsif obj.respond_to? :code 'Doodad' end ctx.schema.types[type_name] || raise('boom') } } ) end def schema GraphQL::Schema.from_definition( definition, default_resolve: resolvers ) end def test_querying_union_types res = schema.execute(<<~EOQUERY) query { widget { ... on Wimpel { id } ... on Doodad { code } } } EOQUERY assert_equal({ 'widget' => [{ 'id' => 'i am wimpel' }, { 'code' => 'i am doodad' }] }, res['data']) end end end
In reality our schema lives in a standlone package (Gem) and we have an implementation of the resolver map in our actual application, the schema is used by other teams too. This test-case in the schema repo helps serve as documentation on how this feature is supposed to be used with the SDL rather than the DSL.
Top comments (0)