graphql-ruby icon indicating copy to clipboard operation
graphql-ruby copied to clipboard

Footgun: Using `method:` kwarg w/ defined resolver method

Open cocoahero opened this issue 1 month ago • 1 comments

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?

cocoahero avatar Dec 03 '25 19:12 cocoahero

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.

rmosolgo avatar Dec 03 '25 19:12 rmosolgo