Skip to content

Commit 33d0097

Browse files
rtymchykrylanc
authored andcommitted
feat: Support Interfaces (#27)
* Support interfaces * Touch up README * Add tests * Clean up * Better test name * Adjust API * Lint
1 parent df1761d commit 33d0097

File tree

7 files changed

+108
-2
lines changed

7 files changed

+108
-2
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,17 @@ class BaseObject < GraphQL::Schema::Object
4444
end
4545
```
4646

47+
Include the `ApolloFederation::Interface` module in your base interface module:
48+
49+
```ruby
50+
module BaseInterface
51+
include GraphQL::Schema::Interface
52+
include ApolloFederation::Interface
53+
54+
field_class BaseField
55+
end
56+
```
57+
4758
Finally, include the `ApolloFederation::Schema` module in your schema:
4859

4960
```ruby

lib/apollo-federation.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require 'apollo-federation/version'
44
require 'apollo-federation/schema'
55
require 'apollo-federation/object'
6+
require 'apollo-federation/interface'
67
require 'apollo-federation/field'
78
require 'apollo-federation/tracing/proto'
89
require 'apollo-federation/tracing/node_map'

lib/apollo-federation/federated_document_from_schema_definition.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ def build_object_type_node(object_type)
2626
merge_directives(object_node, object_type.metadata[:federation_directives])
2727
end
2828

29+
def build_interface_type_node(interface_type)
30+
field_node = super
31+
merge_directives(field_node, interface_type.metadata[:federation_directives])
32+
end
33+
2934
def build_field_node(field_type)
3035
field_node = super
3136
merge_directives(field_node, field_type.metadata[:federation_directives])

lib/apollo-federation/interface.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# frozen_string_literal: true
2+
3+
require 'apollo-federation/has_directives'
4+
5+
module ApolloFederation
6+
module Interface
7+
def self.included(klass)
8+
klass.definition_methods do
9+
include DefinitionMethods
10+
end
11+
end
12+
13+
module DefinitionMethods
14+
include HasDirectives
15+
16+
def extend_type
17+
add_directive(name: 'extends')
18+
end
19+
20+
def key(fields:)
21+
add_directive(
22+
name: 'key',
23+
arguments: [
24+
name: 'fields',
25+
values: fields,
26+
],
27+
)
28+
end
29+
end
30+
end
31+
end

lib/apollo-federation/object.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ def self.included(klass)
1111
module ClassMethods
1212
include HasDirectives
1313

14-
# TODO: We should support extending interfaces at some point
1514
def extend_type
1615
add_directive(name: 'extends')
1716
end

lib/apollo-federation/schema.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def to_graphql
2929
end
3030

3131
possible_entities = orig_defn.types.values.select do |type|
32-
!type.introspection? && !type.default_scalar? &&
32+
!type.introspection? && !type.default_scalar? && type.is_a?(GraphQL::ObjectType) &&
3333
type.metadata[:federation_directives]&.any? { |directive| directive[:name] == 'key' }
3434
end
3535

spec/apollo-federation/service_field_spec.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require 'apollo-federation/schema'
66
require 'apollo-federation/field'
77
require 'apollo-federation/object'
8+
require 'apollo-federation/interface'
89

910
RSpec.describe ApolloFederation::ServiceField do
1011
let(:base_schema) do
@@ -144,6 +145,64 @@ def execute_sdl(schema)
144145
)
145146
end
146147

148+
it 'returns valid SDL for interface types' do
149+
base_interface = Module.new do
150+
include GraphQL::Schema::Interface
151+
include ApolloFederation::Interface
152+
153+
graphql_name 'Interface'
154+
end
155+
156+
product = Module.new do
157+
include base_interface
158+
159+
graphql_name 'Product'
160+
161+
key fields: :upc
162+
field :upc, String, null: false
163+
end
164+
165+
book = Class.new(base_object) do
166+
implements product
167+
168+
graphql_name 'Book'
169+
170+
extend_type
171+
172+
key fields: :upc
173+
field :upc, String, null: false, external: true
174+
end
175+
176+
pen = Class.new(base_object) do
177+
implements product
178+
179+
graphql_name 'Pen'
180+
181+
key fields: :upc
182+
field :upc, String, null: false
183+
end
184+
185+
schema = Class.new(base_schema) do
186+
orphan_types book, pen
187+
end
188+
189+
expect(execute_sdl(schema)).to match_sdl(
190+
<<~GRAPHQL,
191+
type Book implements Product @extends @key(fields: "upc") {
192+
upc: String! @external
193+
}
194+
195+
type Pen implements Product @key(fields: "upc") {
196+
upc: String!
197+
}
198+
199+
interface Product @key(fields: "upc") {
200+
upc: String!
201+
}
202+
GRAPHQL
203+
)
204+
end
205+
147206
context 'when a Query object is provided' do
148207
it 'returns valid SDL for @key directives' do
149208
product = Class.new(base_object) do

0 commit comments

Comments
 (0)