diff --git a/lib/apollo-federation/object.rb b/lib/apollo-federation/object.rb index 474079dc1..8161ea2fc 100644 --- a/lib/apollo-federation/object.rb +++ b/lib/apollo-federation/object.rb @@ -24,6 +24,10 @@ def inaccessible add_directive(name: 'inaccessible') end + def interface_object + add_directive(name: 'interfaceObject') + end + def key(fields:, camelize: true) add_directive( name: 'key', diff --git a/lib/apollo-federation/schema.rb b/lib/apollo-federation/schema.rb index 1dfbd7444..36f35d8ab 100644 --- a/lib/apollo-federation/schema.rb +++ b/lib/apollo-federation/schema.rb @@ -12,15 +12,11 @@ def self.included(klass) end module CommonMethods - FEDERATION_2_PREFIX = <<~SCHEMA - extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") - - SCHEMA + DEFAULT_LINK_NAMESPACE = 'federation'.freeze def federation(version: '1.0', link: {}) @federation_version = version - @link = { as: 'federation' }.merge(link) + @link = { as: DEFAULT_LINK_NAMESPACE }.merge(link) end def federation_version @@ -35,7 +31,7 @@ def federation_sdl(context: nil) document_from_schema = FederatedDocumentFromSchemaDefinition.new(self, context: context) output = GraphQL::Language::Printer.new.print(document_from_schema.document) - output.prepend(FEDERATION_2_PREFIX) if federation_2? + output.prepend(federation_2_prefix) if federation_2? output end @@ -61,9 +57,11 @@ def query(new_query_object = nil) private def federation_2_prefix + federation_namespace = ", as: \"#{link_namespace}\"" if link_namespace != DEFAULT_LINK_NAMESPACE + <<~SCHEMA extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0", as: "#{link_namespace}") + @link(url: "https://specs.apollo.dev/federation/v2.3"#{federation_namespace}) SCHEMA end diff --git a/spec/apollo-federation/schema_spec.rb b/spec/apollo-federation/schema_spec.rb index 5c8824105..407e5e460 100644 --- a/spec/apollo-federation/schema_spec.rb +++ b/spec/apollo-federation/schema_spec.rb @@ -22,6 +22,15 @@ expect(schema.federation_version).to eq('2.0') end + + it 'returns the specified version when set' do + schema = Class.new(GraphQL::Schema) do + include ApolloFederation::Schema + federation version: '2.3' + end + + expect(schema.federation_version).to eq('2.3') + end end describe '.federation_2?' do @@ -61,6 +70,15 @@ expect(schema.federation_2?).to be(true) end + it 'returns true when the version is a float greater than 2.0' do + schema = Class.new(GraphQL::Schema) do + include ApolloFederation::Schema + federation version: 2.3 + end + + expect(schema.federation_2?).to be(true) + end + it 'returns true when the version is a string greater than 2.0' do schema = Class.new(GraphQL::Schema) do include ApolloFederation::Schema @@ -69,5 +87,14 @@ expect(schema.federation_2?).to be(true) end + + it 'returns true when the version is a string greater than 2.0' do + schema = Class.new(GraphQL::Schema) do + include ApolloFederation::Schema + federation version: '2.3' + end + + expect(schema.federation_2?).to be(true) + end end end diff --git a/spec/apollo-federation/service_field_v2_spec.rb b/spec/apollo-federation/service_field_v2_spec.rb index b5c2d5f2c..4a5ac9004 100644 --- a/spec/apollo-federation/service_field_v2_spec.rb +++ b/spec/apollo-federation/service_field_v2_spec.rb @@ -109,7 +109,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product { upc: String! @@ -144,7 +144,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends { upc: String! @@ -180,7 +180,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Position @federation__shareable { x: Int! @@ -217,7 +217,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Position @federation__inaccessible { x: Int! @@ -254,7 +254,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3", as: "fed2") type Product @fed2__extends { upc: String! @@ -290,7 +290,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3", as: "fed2") type Position @fed2__shareable { x: Int! @@ -327,7 +327,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3", as: "fed2") type Position @fed2__inaccessible { x: Int! @@ -363,7 +363,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3", as: "fed2") type Product @fed2__key(fields: "upc") { upc: String! @@ -376,7 +376,7 @@ def execute_sdl(schema) ) end - it 'returns valid SDL for @external directives' do + it 'returns valid SDL for @external directives with custom namespace' do product = Class.new(base_object) do graphql_name 'Product' extend_type @@ -394,7 +394,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3", as: "fed2") type Product @fed2__extends @fed2__key(fields: "upc") { price: Int @@ -403,6 +403,32 @@ def execute_sdl(schema) GRAPHQL ) end + + it 'returns valid SDL for @interfaceObject directives with custom namespace' do + product = Class.new(base_object) do + graphql_name 'Product' + interface_object + key fields: :id + + field :id, 'ID', null: false + end + + schema = Class.new(base_schema) do + orphan_types product + federation version: '2.3', link: { as: 'fed2' } + end + + expect(execute_sdl(schema)).to match_sdl( + <<~GRAPHQL, + extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3", as: "fed2") + + type Product @fed2__interfaceObject @fed2__key(fields: "id") { + id: ID! + } + GRAPHQL + ) + end end it 'returns valid SDL for inaccessible interface types' do @@ -444,7 +470,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Book implements Product { upc: String! @@ -507,7 +533,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Book implements Product @federation__extends @federation__key(fields: "upc") { upc: String! @federation__external @@ -547,7 +573,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__key(fields: "upc") { upc: String! @@ -578,7 +604,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__key(fields: "upc") { upc: String! @@ -606,7 +632,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__key(fields: "upc") @federation__key(fields: "name") { name: String @@ -634,7 +660,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends @federation__key(fields: "upc") { price: Int @@ -644,6 +670,32 @@ def execute_sdl(schema) ) end + it 'returns valid SDL for @interfaceObject directives' do + product = Class.new(base_object) do + graphql_name 'Product' + interface_object + key fields: :id + + field :id, 'ID', null: false + end + + schema = Class.new(base_schema) do + orphan_types product + federation version: '2.3' + end + + expect(execute_sdl(schema)).to match_sdl( + <<~GRAPHQL, + extend schema + @link(url: "https://specs.apollo.dev/federation/v2.3") + + type Product @federation__interfaceObject @federation__key(fields: "id") { + id: ID! + } + GRAPHQL + ) + end + it 'returns valid SDL for @shareable directives' do position = Class.new(base_object) do graphql_name 'Position' @@ -666,7 +718,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Position { x: Int! @federation__shareable @@ -702,7 +754,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Position { x: Int! @federation__inaccessible @@ -734,7 +786,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends @federation__key(fields: "id") { id: ID! @@ -770,7 +822,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends @federation__key(fields: "upc") { price: Int @@ -805,7 +857,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends @federation__key(fields: "upc") { price: Int @federation__external @@ -834,7 +886,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__key(fields: "productId") { productId: String! @@ -862,7 +914,7 @@ def execute_sdl(schema) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends @federation__key(fields: "product_id") { options: [String!]! @federation__requires(fields: "my_id") @@ -895,7 +947,7 @@ def self.visible?(context) expect(execute_sdl(schema)).to match_sdl( <<~GRAPHQL, extend schema - @link(url: "https://specs.apollo.dev/federation/v2.0") + @link(url: "https://specs.apollo.dev/federation/v2.3") type Product @federation__extends @federation__key(fields: "upc") { upc: String! @federation__external