Can't use fields with the name object/context, reserved terms?
ioev opened this issue · 3 comments
Describe the bug
I have a type that is using an "object" and "context" field and it ends up returning the graphql object/context instead. Seems related to #1320 but I can't figure out how to make any of the recommended fixes work for me.
Versions
graphql
version: 2.3.5
rails
: 7.0.8
GraphQL schema
module Types
class Permission < SecureObject
description "A permission"
field :id, Integer
field :description, String
field :object, String, method: :permission_object
field :action, String
field :context, String, method: :permission_context
end
end
Steps to reproduce
Query for this type along with the object/context fields.
Expected behavior
It should return the object/context properties, as defined in permission_object/permission_context.
Actual behavior
I get back a response that looks like:
"description":"Read all asset"
"object":"#<Permission:0x00007f2129c68238>"
"action":"read"
"context":"#<GraphQL::Query::Context:0x00007f2129d73650>"
"__typename":"Permission"
}
Additional context
Even though I have added method: :permission_object
it doesn't matter if I define this method or not because it seems to be ignored. Are reserved keywords such as object/context completely off limits now? I'd prefer to not have to change my schema to work around this if possible.
Hey! Sorry for the trouble. Was this working in a previous GraphQL-Ruby version? I would expect it to have not worked for a long time ...
I wrote up a little replication script and it emitted this warning:
Thing's `field :context` conflicts with a built-in method, use `resolver_method:` to pick a different resolver method for this field (for example, `resolver_method: :resolve_context` and `def resolve_context`). Or use `method_conflict_warning: false` to suppress this warning.
and:
Thing's `field :object` conflicts with a built-in method, use `resolver_method:` to pick a different resolver method for this field (for example, `resolver_method: :resolve_object` and `def resolve_object`). Or use `method_conflict_warning: false` to suppress this warning.
Does your app emit those warnings when it boots? (If not, I may need to check the code and make sure it's working right...)
The solution mentioned in those warnings works for me (using resolver_method: ...
to pick a new method name, then implementing the method to make the calls). Here's a script using that approach:
require "bundler/inline"
gemfile do
gem "graphql", "2.3.5"
end
class MySchema < GraphQL::Schema
class Thing < GraphQL::Schema::Object
field :context, String, resolver_method: :resolve_context
def resolve_context
object.context
end
field :object, String, resolver_method: :resolve_object
def resolve_object
object.object
end
end
class Query < GraphQL::Schema::Object
field :thing, Thing
def thing
OpenStruct.new(context: "This is the context", object: "This is the object")
end
end
query(Query)
end
query_str = "{ thing { object context } }"
pp MySchema.execute(query_str).to_h
# {"data"=>{"thing"=>{"object"=>"This is the object", "context"=>"This is the context"}}}
What do you think of that approach?
Thank you for the quick reply! This is new functionality that was added while using graphql 2.3.0, though I upgraded to 2.3.5 to make sure there wasn't a fix I was missing.
I took a closer look at the log files (this app is quite noisy) and did find the warning that you mentioned. It doesn't display on boot, but displays alongside one of 12 or so queries that are resolved, so I ended up not noticing it:
web | Permission's `field :context` conflicts with a built-in method, use `resolver_method:` to pick a different resolver method for this field (for example, `resolver_method: :resolve_context` and `def resolve_context`). Or use `method_conflict_warning: false` to suppress this warning.
Using resolver_method:
also corrects the issue, and I can use the field names that I want here:
module Types
class Permission < SecureObject
description "A permission"
field :id, Integer
field :description, String
field :object, String, resolver_method: :permission_object
field :action, String
field :context, String, resolver_method: :permission_context
def permission_object
object.object
end
def permission_context
object.context
end
end
end
I think my biggest sticking point was that I got caught up trying to use method:
to override here (which we've used elsewhere in a similar way) rather than resolver_method:
, which I didn't know existed at the time. I've since realized that this specific use case is even documented on https://graphql-ruby.org/fields/introduction.
I wonder if since these 2 methods are so similar in usage/name, could they be combined into a single method? I'm guessing there must have been a reason to not just allow something like:
field :context, String, method: :permission_context
In any case, thanks again for your help!
Glad it worked for you!
method
and resolver_method
are very similar, but they were intentionally separated back in #1961. I don't remember the details but the concerns there would have to be addressed in order to re-merge them in some way... And I don't plan to wade back in on that 😅