Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invisible object class makes interfaces ivislbe for all objects that extend it #4564

Open
bessey opened this issue Jul 24, 2023 · 1 comment

Comments

@bessey
Copy link
Contributor

bessey commented Jul 24, 2023

Describe the bug

Given a GraphQL object class which implements one or more interfaces, and which is extended by another object class, if the original object is not visible?, its interfaces are not exposed on the extending class.

Versions

I am on 1.13 but I have reproduced with 2.0 latest:

Demo

require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "graphql", "~> 2.0"
end

class Account
  def initialize(id)
    @id = id
  end

  attr_reader :id
end

module Identifiable
  include GraphQL::Schema::Interface

  field :id, ID, null: false
end

class AccountType < GraphQL::Schema::Object
  implements Identifiable

  # FIX: Comment this method out
  def self.visible?(_context)
    false
  end
end

class NewAccountType < AccountType
  def self.visible?(_context)
    true
  end
end

class QueryType < GraphQL::Schema::Object
  field :account, NewAccountType, null: true

  def account
    Account.new(1)
  end
end

class MySchema < GraphQL::Schema
  query(QueryType)
end

query = <<-GRAPHQL
  query {
    account {
      id
    }
  }
GRAPHQL

result = MySchema.execute(query, variables: {}, context: {})
puts result.to_h

Steps to reproduce

Run the above with and without the commented section.

Expected behavior

$ ruby ./demo.rb
{"data"=>{"account"=>{"id"=>"1"}}}

Actual behavior

$ ruby ./demo.rb
{"errors"=>[{"message"=>"Field 'id' doesn't exist on type 'NewAccount'", "locations"=>[{"line"=>3, "column"=>7}], "path"=>["query", "account", "id"], "extensions"=>{"code"=>"undefinedField", "typeName"=>"NewAccount", "fieldName"=>"id"}}]}
@rmosolgo
Copy link
Owner

Hey, thanks for the detailed report. I'll have to check back in the archives to determine whether this is a feature or a bug 😆 . I have a hunch it was addressed in a previous issue or PR.

In any case, the described behavior comes from here:

def visible?(ctx)
warden = Warden.from_context(ctx)
(@object_type.respond_to?(:visible?) ? warden.visible_type?(@object_type, ctx) : true) &&
(@abstract_type.respond_to?(:visible?) ? warden.visible_type?(@abstract_type, ctx) : true)
end

You could customize how interface implementations and union memberships are determined to be visible by making a custom subclass of TypeMembership and attaching it to your base interface and base union using the type_membership_class(...) config:

def type_membership_class(membership_class = nil)

def type_membership_class(membership_class = nil)

That would allow you to opt out of this behavior in the meantime.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants