I am either missing something or it does not appear to be possible to set up circularly referencing objects with the class based API if you're not using the rails autoloader. The example in the introductory blog post
http://rmosolgo.github.io/blog/2018/03/25/why-a-new-schema-definition-api/
# Let's assume that `Post` is loaded first.
# app/graphql/types/post.rb
module Types # 1, evaluation starts here
class Post < BaseObject # 2, and naturally flows here, constant `Types::Post` is initialized as a class extending BaseObject
field :author, Types::User, null: false # 3, but when evaluating `Types::User`, jumps down below
end # 9, execution resumes here after loading `Types::User`
end # 10
# app/graphql/types/user.rb
module Types # 4, Rails opens this file looking for `Types::User`
class User < BaseObject # 5, constant `Types::User` is initialized
field :posts, [Types::Post], null: false # 6, this line finishes without jumping, because `Types::Post` is _already_ initialized (see `# 2` above)
end # 7
end # 8
only works because the rails autoloader kicks in on Module#const_missing at step 3. If we were to manually require in the files, we would have the following execution order.
# Let's assume that `Post` is loaded first.
# app/graphql/types/post.rb
require 'graphql/types/user' #1, evaluation starts here
module Types
class Post < BaseObject
field :author, Types::User, null: false
end
end
# app/graphql/types/user.rb
require 'graphql/types/post' #2, evaluation jumps to the user file, the require for types/post returns false as we are in the process of loading it
module Types #3 the Types constant is created
class User < BaseObject #4 the User constant is created
field :posts, [Types::Post], null: false #5 we blow up, the Types::Post constant is not found
end
end
This can be seen in the stack trace you get running the above code
NameError: uninitialized constant Types::Post
....types/user.rb:5:in `<class:User>'
.../types/user.rb:4:in `<module:Types>'
.../types/user.rb:3:in `<top (required)>'
.../types/post.rb:1:in `<top (required)>'
.../types/query_type.rb:6:in `<top (required)>'
(Ruby 2.4.3, grapqhl 1.8.11)
Is the rails autoloader a hard dependency of the new schema definition API or is there a different way to solve this problem?
Hi, good question!
It's not well documented but you can also use strings in cases like this, for example:
field :author, "Types::User", null: false
Here's a little runable example:
require "graphql"
class Query < GraphQL::Schema::Object
field :a, "TypeA", null: false
end
class TypeA < GraphQL::Schema::Object
field :b, "TypeB", null: false
end
class TypeB < GraphQL::Schema::Object
field :a, "TypeA", null: false
end
class Schema < GraphQL::Schema
query(Query)
end
root = OpenStruct.new(a: OpenStruct.new(b: OpenStruct.new(a: 1)))
puts Schema.execute("{ a { b { a { __typename } } } }", root_value: root ).to_h
{"data"=>{"a"=>{"b"=>{"a"=>{"__typename"=>"TypeA"}}}}}
Would using strings work in your case?
Hey, that works perfectly!
Thanks
Most helpful comment
Hi, good question!
It's not well documented but you can also use strings in cases like this, for example:
Here's a little runable example:
Would using strings work in your case?