Graphql-ruby: Relay Node Fields not Added To Query Type

Created on 2 May 2020  路  3Comments  路  Source: rmosolgo/graphql-ruby

Describe the bug

As the title says, the Relay node fields are not added to the query type.

Versions

graphql version: 1.10.7
rails (or other framework): 6.0.2.2

GraphQL query

query {
  node(id: "Q2Fwc3VsZS0z") {
     ... on Node {
        id
     }
  }
}
{
  "errors": [
    {
      "message": "Field 'node' doesn't exist on type 'Query'",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "query",
        "node"
      ],
      "extensions": {
        "code": "undefinedField",
        "typeName": "Query",
        "fieldName": "node"
      }
    }
  ]
}

Steps to reproduce

Add the following fields to your query_type.rb

    # Implement the relay spec
    add_field GraphQL::Types::Relay::NodeField
    add_field GraphQL::Types::Relay::NodesField

Expected behavior

The node and nodes fields should be added to the schema.

Actual behavior

They're not added to the schema.

Additional context

This issue can be solved by downgrading to Graphql-ruby version 1.10.5 opposed to the original version

Most helpful comment

I bet the problem is about orphan_types: if there are no registered implementations of the Node interface, then those fields will be hidden from the schema because their return type is invalid.

Here's a working example:

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'graphql', "1.10.7"
end

class Thing < GraphQL::Schema::Object
  implements GraphQL::Types::Relay::Node
end

class Query < GraphQL::Schema::Object
  add_field GraphQL::Types::Relay::NodeField
  add_field GraphQL::Types::Relay::NodesField
end


class Schema < GraphQL::Schema
  query(Query)

  def self.resolve_type(*)
    Thing
  end

  def self.object_from_id(id, ctx)
    { id: id }
  end

  orphan_types(Thing)
end


pp Schema.execute <<~GRAPHQL
    {
      node(id: "abcd") {
        ...on Thing {
          id
        }
      }

      nodes(ids: ["abcd"]) {
        ...on Thing {
          id
        }
      }
    }
  GRAPHQL
# => #<GraphQL::Query::Result @query=... @to_h={"data"=>{"node"=>{"id"=>"abcd"}, "nodes"=>[{"id"=>"abcd"}]}}>

To make sure that Node (and its implementations) are properly registered in the schema:

  • Add object types to orphan_types (as shown above)
  • Or, add fields that return those object types

(The problem is, GraphQL-Ruby can only find object times that are linked to the schema in some way; orphan_types is there to add types that aren't otherwise referenced.)

Let me know if that doesn't fix it for you!

All 3 comments

I bet the problem is about orphan_types: if there are no registered implementations of the Node interface, then those fields will be hidden from the schema because their return type is invalid.

Here's a working example:

require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'graphql', "1.10.7"
end

class Thing < GraphQL::Schema::Object
  implements GraphQL::Types::Relay::Node
end

class Query < GraphQL::Schema::Object
  add_field GraphQL::Types::Relay::NodeField
  add_field GraphQL::Types::Relay::NodesField
end


class Schema < GraphQL::Schema
  query(Query)

  def self.resolve_type(*)
    Thing
  end

  def self.object_from_id(id, ctx)
    { id: id }
  end

  orphan_types(Thing)
end


pp Schema.execute <<~GRAPHQL
    {
      node(id: "abcd") {
        ...on Thing {
          id
        }
      }

      nodes(ids: ["abcd"]) {
        ...on Thing {
          id
        }
      }
    }
  GRAPHQL
# => #<GraphQL::Query::Result @query=... @to_h={"data"=>{"node"=>{"id"=>"abcd"}, "nodes"=>[{"id"=>"abcd"}]}}>

To make sure that Node (and its implementations) are properly registered in the schema:

  • Add object types to orphan_types (as shown above)
  • Or, add fields that return those object types

(The problem is, GraphQL-Ruby can only find object times that are linked to the schema in some way; orphan_types is there to add types that aren't otherwise referenced.)

Let me know if that doesn't fix it for you!

Hey, adding in the orphan_types manually seems to work but if you have 100s of types It could get a bit messy, is there a more elegant solution?

I had it working without the orphan type

Hey, adding in the orphan_types manually seems to work but if you have 100s of types It could get a bit messy, is there a more elegant solution?

If you have a predictable way of naming the graphql_name from the model name then you can dynamically evaluate it.
example: User =>Types::UserType, Article => Types::ArticleType

def self.resolve_type(type, obj, ctx)
    klass = obj.class
    gql_type = "Types::#{klass}Type"
    # if you have inheritance in models & type
    # unless const_defined? gql_type
      # gql_type = "Types::#{klass.superclass}Type"
    # end
    gql_type.constantize
end
Was this page helpful?
0 / 5 - 0 ratings

Related issues

KevinColemanInc picture KevinColemanInc  路  3Comments

EAdeveloper picture EAdeveloper  路  3Comments

gastonmorixe picture gastonmorixe  路  3Comments

amozoss picture amozoss  路  3Comments

pareeohnos picture pareeohnos  路  3Comments