diff --git a/lib/apollo-federation/federated_document_from_schema_definition.rb b/lib/apollo-federation/federated_document_from_schema_definition.rb index 11e197533..8d2f13d7d 100644 --- a/lib/apollo-federation/federated_document_from_schema_definition.rb +++ b/lib/apollo-federation/federated_document_from_schema_definition.rb @@ -69,7 +69,7 @@ def build_field_node(field_type) def build_type_definition_nodes(types) non_federation_types = types.select do |type| if query_type?(type) - !type.fields.values.all? { |field| FEDERATION_QUERY_FIELDS.include?(field.graphql_name) } + !warden.fields(type).all? { |field| FEDERATION_QUERY_FIELDS.include?(field.graphql_name) } else !FEDERATION_TYPES.include?(type.graphql_name) end diff --git a/lib/apollo-federation/schema.rb b/lib/apollo-federation/schema.rb index 3aa0448bf..ba7e6d24e 100644 --- a/lib/apollo-federation/schema.rb +++ b/lib/apollo-federation/schema.rb @@ -81,9 +81,9 @@ def schema_entities # Walk through all of the types and determine which ones are entities (any type with a # "key" directive) - types_schema.types.values.select do |type| + types_schema.send(:non_introspection_types).values.flatten.select do |type| # TODO: Interfaces can have a key... - !type.introspection? && type.include?(ApolloFederation::Object) && + type.include?(ApolloFederation::Object) && type.federation_directives&.any? { |directive| directive[:name] == 'key' } end end diff --git a/spec/apollo-federation/service_field_v2_spec.rb b/spec/apollo-federation/service_field_v2_spec.rb index 60d5fac57..d7e80e9d4 100644 --- a/spec/apollo-federation/service_field_v2_spec.rb +++ b/spec/apollo-federation/service_field_v2_spec.rb @@ -2043,6 +2043,94 @@ def hello ) end end + + if Gem::Version.new(GraphQL::VERSION) >= Gem::Version.new('1.13.0') + context 'with visibility checks on types and fields with duplicate names' do + let(:schema) do + regular_product = Class.new(base_object) do + graphql_name 'Product' + key fields: :upc + + field :upc, String, null: false + field :regular_field, String, null: true + + def self.visible?(context) + context[:graph_type] == :regular + end + end + + admin_product = Class.new(base_object) do + graphql_name 'Product' + key fields: :upc + + field :upc, String, null: false + field :admin_field, String, null: true + + def self.visible?(context) + context[:graph_type] == :admin + end + end + + query_obj = Class.new(base_object) do + graphql_name 'Query' + + field :hello, String, null: false + + field :product, regular_product, null: true do + def visible?(context) + context[:graph_type] == :regular + end + end + + field :product, admin_product, null: true do + def visible?(context) + context[:graph_type] == :admin + end + end + end + + Class.new(base_schema) do + query query_obj + end + end + + it 'applies visibility checks during SDL generation to expose schema members' do + results = schema.execute('{ _service { sdl } }', context: { graph_type: :regular }) + + expect(results.dig('data', '_service', 'sdl')).to match_sdl( + <<~GRAPHQL, + type Product @key(fields: "upc") { + regularField: String + upc: String! + } + + type Query { + hello: String! + product: Product + } + GRAPHQL + ) + end + + it 'applies visibility checks during SDL generation to expose alternate schema members' do + results = schema.execute('{ _service { sdl } }', context: { graph_type: :admin }) + + expect(results.dig('data', '_service', 'sdl')).to match_sdl( + <<~GRAPHQL, + type Product @key(fields: "upc") { + adminField: String + upc: String! + } + + type Query { + hello: String! + product: Product + } + GRAPHQL + ) + end + end + end end if Gem::Version.new(GraphQL::VERSION) < Gem::Version.new('1.12.0')