apollo-federation 3.0.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +62 -0
- data/lib/apollo-federation/entities_field.rb +20 -12
- data/lib/apollo-federation/federated_document_from_schema_definition.rb +11 -3
- data/lib/apollo-federation/field.rb +44 -3
- data/lib/apollo-federation/interface.rb +4 -0
- data/lib/apollo-federation/object.rb +8 -0
- data/lib/apollo-federation/schema.rb +35 -1
- data/lib/apollo-federation/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3133ca250d8e6ed9689a172c2fdaf373ae0ee0fcb371848cffeb75938f97be62
|
4
|
+
data.tar.gz: 5467c27805efb85724124ede7c1014abfffbd679aba915e188ec74edfc8a8051
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 446e436bbc11437122d01ba8c49097919b0c1d281ab40427ea330d3494d05dc21d10e3795394ef41bea9b24d5d33eb9c7ba854116f96cb32cc88318c51cde0ac
|
7
|
+
data.tar.gz: b22c3f55c0fb6114f68aefcedd08ed5f8acaebda5699f26be21e4cc9ad61c3d225aa6beb1f1253e64533dae56da6d869c8962a4b6aa75d548a9e032e01d3a8dc
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
# [3.3.0](https://github.com/Gusto/apollo-federation-ruby/compare/v3.2.0...v3.3.0) (2022-08-24)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* introduce optional `resolve_references` method ([#206](https://github.com/Gusto/apollo-federation-ruby/issues/206)) ([1e3b631](https://github.com/Gusto/apollo-federation-ruby/commit/1e3b631609e1dfec8c3f126cd9dc8e0a2b3a0a57))
|
7
|
+
|
8
|
+
# [3.2.0](https://github.com/Gusto/apollo-federation-ruby/compare/v3.1.0...v3.2.0) (2022-08-15)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* allow custom namespace for linked directives ([03fdfea](https://github.com/Gusto/apollo-federation-ruby/commit/03fdfeafaaea3c98ca4b7a734ce760ea08410530))
|
14
|
+
|
15
|
+
# [3.1.0](https://github.com/Gusto/apollo-federation-ruby/compare/v3.0.0...v3.1.0) (2022-06-21)
|
16
|
+
|
17
|
+
|
18
|
+
### Features
|
19
|
+
|
20
|
+
* Support Federation v2 ([#196](https://github.com/Gusto/apollo-federation-ruby/issues/196)) ([238736c](https://github.com/Gusto/apollo-federation-ruby/commit/238736cdb6f12121ce2a295c7a28fba3990012b9)), closes [/www.apollographql.com/docs/federation/federation-2/moving-to-federation-2/#opt-in-to-federation-2](https://github.com//www.apollographql.com/docs/federation/federation-2/moving-to-federation-2//issues/opt-in-to-federation-2)
|
21
|
+
|
1
22
|
# [3.0.0](https://github.com/Gusto/apollo-federation-ruby/compare/v2.2.4...v3.0.0) (2022-04-05)
|
2
23
|
|
3
24
|
|
data/README.md
CHANGED
@@ -61,6 +61,15 @@ class MySchema < GraphQL::Schema
|
|
61
61
|
end
|
62
62
|
```
|
63
63
|
|
64
|
+
**Optional:** To opt in to Federation v2, specify the version in your schema:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
class MySchema < GraphQL::Schema
|
68
|
+
include ApolloFederation::Schema
|
69
|
+
federation version: '2.0'
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
64
73
|
## Example
|
65
74
|
|
66
75
|
The [`example`](./example/) folder contains a Ruby implementation of Apollo's [`federation-demo`](https://github.com/apollographql/federation-demo). To run it locally, install the Ruby dependencies:
|
@@ -160,6 +169,59 @@ end
|
|
160
169
|
```
|
161
170
|
See [field set syntax](#field-set-syntax) for more details on the format of the `fields` option.
|
162
171
|
|
172
|
+
### The `@shareable` directive (Apollo Federation v2)
|
173
|
+
|
174
|
+
[Apollo documentation](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#shareable)
|
175
|
+
|
176
|
+
Call `shareable` within your class definition:
|
177
|
+
|
178
|
+
```ruby
|
179
|
+
class User < BaseObject
|
180
|
+
shareable
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
Pass the `shareable: true` option to your field definition:
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
class User < BaseObject
|
188
|
+
field :id, ID, null: false, shareable: true
|
189
|
+
end
|
190
|
+
```
|
191
|
+
|
192
|
+
### The `@inaccessible` directive (Apollo Federation v2)
|
193
|
+
|
194
|
+
[Apollo documentation](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#inaccessible)
|
195
|
+
|
196
|
+
Call `inaccessible` within your class definition:
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
class User < BaseObject
|
200
|
+
inaccessible
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
204
|
+
Pass the `inaccessible: true` option to your field definition:
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
class User < BaseObject
|
208
|
+
field :id, ID, null: false, inaccessible: true
|
209
|
+
end
|
210
|
+
```
|
211
|
+
|
212
|
+
### The `@override` directive (Apollo Federation v2)
|
213
|
+
|
214
|
+
[Apollo documentation](https://www.apollographql.com/docs/federation/federated-types/federated-directives/#override)
|
215
|
+
|
216
|
+
Pass the `override:` option to your field definition:
|
217
|
+
|
218
|
+
```ruby
|
219
|
+
class Product < BaseObject
|
220
|
+
field :id, ID, null: false
|
221
|
+
field :inStock, Boolean, null: false, override: { from: 'Products' }
|
222
|
+
end
|
223
|
+
```
|
224
|
+
|
163
225
|
### Field set syntax
|
164
226
|
|
165
227
|
Field sets can be either strings encoded with the Apollo Field Set [syntax]((https://www.apollographql.com/docs/apollo-server/federation/federation-spec/#scalar-_fieldset)) or arrays, hashes and snake case symbols that follow the graphql-ruby conventions:
|
@@ -27,8 +27,10 @@ module ApolloFederation
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def _entities(representations:)
|
30
|
-
representations.
|
31
|
-
|
30
|
+
grouped_references = representations.group_by { |r| r[:__typename] }
|
31
|
+
|
32
|
+
final_results = []
|
33
|
+
grouped_references.each do |typename, references|
|
32
34
|
# TODO: Use warden or schema?
|
33
35
|
type = context.warden.get_type(typename)
|
34
36
|
if type.nil? || type.kind != GraphQL::TypeKinds::OBJECT
|
@@ -40,21 +42,27 @@ module ApolloFederation
|
|
40
42
|
# TODO: What if the type is an interface?
|
41
43
|
type_class = class_of_type(type)
|
42
44
|
|
43
|
-
if type_class.respond_to?(:
|
44
|
-
|
45
|
+
if type_class.respond_to?(:resolve_references)
|
46
|
+
results = type_class.resolve_references(references, context)
|
47
|
+
elsif type_class.respond_to?(:resolve_reference)
|
48
|
+
results = references.map { |reference| type_class.resolve_reference(reference, context) }
|
45
49
|
else
|
46
|
-
|
50
|
+
results = references
|
47
51
|
end
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
results = results.map do |result|
|
54
|
+
context.schema.after_lazy(result) do |resolved_value|
|
55
|
+
# TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference
|
56
|
+
# calls return the same object, it might not have the right type
|
57
|
+
# Right now, apollo-federation just adds a __typename property to the result,
|
58
|
+
# but I don't really like the idea of modifying the resolved object
|
59
|
+
context[resolved_value] = type
|
60
|
+
resolved_value
|
61
|
+
end
|
56
62
|
end
|
63
|
+
final_results = final_results.concat(results)
|
57
64
|
end
|
65
|
+
final_results
|
58
66
|
end
|
59
67
|
|
60
68
|
private
|
@@ -55,20 +55,28 @@ module ApolloFederation
|
|
55
55
|
|
56
56
|
def merge_directives(node, type)
|
57
57
|
if type.is_a?(ApolloFederation::HasDirectives)
|
58
|
-
directives = type.federation_directives
|
58
|
+
directives = type.federation_directives || []
|
59
59
|
else
|
60
60
|
directives = []
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
directives.each do |directive|
|
64
64
|
node = node.merge_directive(
|
65
|
-
name: directive
|
65
|
+
name: directive_name(directive),
|
66
66
|
arguments: build_arguments_node(directive[:arguments]),
|
67
67
|
)
|
68
68
|
end
|
69
69
|
node
|
70
70
|
end
|
71
71
|
|
72
|
+
def directive_name(directive)
|
73
|
+
if schema.federation_2?
|
74
|
+
"#{schema.link_namespace}__#{directive[:name]}"
|
75
|
+
else
|
76
|
+
directive[:name]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
72
80
|
def build_arguments_node(arguments)
|
73
81
|
(arguments || []).map do |arg|
|
74
82
|
GraphQL::Language::Nodes::Argument.new(name: arg[:name], value: arg[:values])
|
@@ -7,10 +7,29 @@ module ApolloFederation
|
|
7
7
|
module Field
|
8
8
|
include HasDirectives
|
9
9
|
|
10
|
-
|
10
|
+
VERSION_1_DIRECTIVES = %i[external requires provides].freeze
|
11
|
+
VERSION_2_DIRECTIVES = %i[shareable inaccessible override].freeze
|
12
|
+
|
13
|
+
def initialize(*args, **kwargs, &block)
|
14
|
+
add_v1_directives(**kwargs)
|
15
|
+
add_v2_directives(**kwargs)
|
16
|
+
|
17
|
+
# Remove the custom kwargs
|
18
|
+
kwargs = kwargs.delete_if do |k, _|
|
19
|
+
VERSION_1_DIRECTIVES.include?(k) || VERSION_2_DIRECTIVES.include?(k)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Pass on the default args:
|
23
|
+
super(*args, **kwargs, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def add_v1_directives(external: nil, requires: nil, provides: nil, **_kwargs)
|
11
29
|
if external
|
12
30
|
add_directive(name: 'external')
|
13
31
|
end
|
32
|
+
|
14
33
|
if requires
|
15
34
|
add_directive(
|
16
35
|
name: 'requires',
|
@@ -23,6 +42,7 @@ module ApolloFederation
|
|
23
42
|
],
|
24
43
|
)
|
25
44
|
end
|
45
|
+
|
26
46
|
if provides
|
27
47
|
add_directive(
|
28
48
|
name: 'provides',
|
@@ -36,8 +56,29 @@ module ApolloFederation
|
|
36
56
|
)
|
37
57
|
end
|
38
58
|
|
39
|
-
|
40
|
-
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_v2_directives(shareable: nil, inaccessible: nil, override: nil, **_kwargs)
|
63
|
+
if shareable
|
64
|
+
add_directive(name: 'shareable')
|
65
|
+
end
|
66
|
+
|
67
|
+
if inaccessible
|
68
|
+
add_directive(name: 'inaccessible')
|
69
|
+
end
|
70
|
+
|
71
|
+
if override
|
72
|
+
add_directive(
|
73
|
+
name: 'override',
|
74
|
+
arguments: [
|
75
|
+
name: 'from',
|
76
|
+
values: override[:from],
|
77
|
+
],
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
nil
|
41
82
|
end
|
42
83
|
end
|
43
84
|
end
|
@@ -16,6 +16,14 @@ module ApolloFederation
|
|
16
16
|
add_directive(name: 'extends')
|
17
17
|
end
|
18
18
|
|
19
|
+
def shareable
|
20
|
+
add_directive(name: 'shareable')
|
21
|
+
end
|
22
|
+
|
23
|
+
def inaccessible
|
24
|
+
add_directive(name: 'inaccessible')
|
25
|
+
end
|
26
|
+
|
19
27
|
def key(fields:, camelize: true)
|
20
28
|
add_directive(
|
21
29
|
name: 'key',
|
@@ -12,9 +12,35 @@ module ApolloFederation
|
|
12
12
|
end
|
13
13
|
|
14
14
|
module CommonMethods
|
15
|
+
FEDERATION_2_PREFIX = <<~SCHEMA
|
16
|
+
extend schema
|
17
|
+
@link(url: "https://specs.apollo.dev/federation/v2.0")
|
18
|
+
|
19
|
+
SCHEMA
|
20
|
+
|
21
|
+
def federation(version: '1.0', link: {})
|
22
|
+
@federation_version = version
|
23
|
+
@link = { as: 'federation' }.merge(link)
|
24
|
+
end
|
25
|
+
|
26
|
+
def federation_version
|
27
|
+
@federation_version || '1.0'
|
28
|
+
end
|
29
|
+
|
30
|
+
def federation_2?
|
31
|
+
Gem::Version.new(federation_version.to_s) >= Gem::Version.new('2.0.0')
|
32
|
+
end
|
33
|
+
|
15
34
|
def federation_sdl(context: nil)
|
16
35
|
document_from_schema = FederatedDocumentFromSchemaDefinition.new(self, context: context)
|
17
|
-
|
36
|
+
|
37
|
+
output = GraphQL::Language::Printer.new.print(document_from_schema.document)
|
38
|
+
output.prepend(FEDERATION_2_PREFIX) if federation_2?
|
39
|
+
output
|
40
|
+
end
|
41
|
+
|
42
|
+
def link_namespace
|
43
|
+
@link[:as]
|
18
44
|
end
|
19
45
|
|
20
46
|
def query(new_query_object = nil)
|
@@ -34,6 +60,14 @@ module ApolloFederation
|
|
34
60
|
|
35
61
|
private
|
36
62
|
|
63
|
+
def federation_2_prefix
|
64
|
+
<<~SCHEMA
|
65
|
+
extend schema
|
66
|
+
@link(url: "https://specs.apollo.dev/federation/v2.0", as: "#{link_namespace}")
|
67
|
+
|
68
|
+
SCHEMA
|
69
|
+
end
|
70
|
+
|
37
71
|
def schema_entities
|
38
72
|
# Create a temporary schema that inherits from this one to extract the types
|
39
73
|
types_schema = Class.new(self)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apollo-federation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Noa Elad
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-08-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: graphql
|