Footgun: Using `method:` kwarg w/ defined resolver method
When a field definition uses the method: keyword argument, it is ignored if the owning object definition has a method named the same as the field.
class MyRootObject
def foo
"hello"
end
end
class QueryRoot < GraphQL::Schema::Object
field :my_field, String, null: false, method: :foo
def my_field
"footgun"
end
end
class Schema < GraphQL::Schema
query(QueryRoot)
end
result = Schema.execute("{ myField }", root_value: MyRootObject.new)
puts result.to_h.dig("data", "myField") # => footgun
Looking at the default resolver resolution logic, this is due to the fact that the object definition is checked before the method: kwarg. The docs state:
By default, fields return values by:
- Trying to call a method on the underlying object; OR
- If the underlying object is a Hash, lookup a key in that hash.
- An optional :fallback_value can be supplied that will be used if the above fail.
As seen above, this is not entirely true.
Internally we have developed a rubocop rule to detect this (happy to share), but its unable to highlight occurrences where the method is defined in an ancestor.
"Fixing" this behavior is likely considered a breaking change, so not sure if its something to address in 3.x?
Thanks for reporting this -- agreed that it sure doesn't seem like it should work this way. I agree that it'd be a good candidate for 3.x. I'm hoping to deprecate the dynamic default field resolution by then, too, so it'd be a chance to address this.