apollo-federation 2.2.4 → 3.2.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 +26 -0
- data/README.md +62 -0
- data/lib/apollo-federation/federated_document_from_schema_definition.rb +11 -3
- data/lib/apollo-federation/field.rb +52 -5
- data/lib/apollo-federation/field_set_serializer.rb +7 -9
- data/lib/apollo-federation/interface.rb +6 -2
- data/lib/apollo-federation/object.rb +10 -2
- 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: fe0ae888b83a68558821badedaaacc8c2e175dbf1aff918f347ec7ca797d8c0a
|
4
|
+
data.tar.gz: ceae483d68658009536a64de692473cebad87d0810027c7c80219df52b7d8cfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3aaba325f9d53ceef358dc287963afe2374ca75d9a6cd3e2b988c9e008e47496238b81eb59c538d4bbb2693a967a52ce72c8efb8c643321480692b3b7666d6c
|
7
|
+
data.tar.gz: 8ed45a0a43cf239ddbb6dbdd8f4375f209efec48f5d9f17282b83b564e9d98c6b41bab51bbaf622b57265ed2d1a93bacacf9e71da54b1205b07c9a3fa762f56a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
# [3.2.0](https://github.com/Gusto/apollo-federation-ruby/compare/v3.1.0...v3.2.0) (2022-08-15)
|
2
|
+
|
3
|
+
|
4
|
+
### Features
|
5
|
+
|
6
|
+
* allow custom namespace for linked directives ([03fdfea](https://github.com/Gusto/apollo-federation-ruby/commit/03fdfeafaaea3c98ca4b7a734ce760ea08410530))
|
7
|
+
|
8
|
+
# [3.1.0](https://github.com/Gusto/apollo-federation-ruby/compare/v3.0.0...v3.1.0) (2022-06-21)
|
9
|
+
|
10
|
+
|
11
|
+
### Features
|
12
|
+
|
13
|
+
* 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)
|
14
|
+
|
15
|
+
# [3.0.0](https://github.com/Gusto/apollo-federation-ruby/compare/v2.2.4...v3.0.0) (2022-04-05)
|
16
|
+
|
17
|
+
|
18
|
+
### Bug Fixes
|
19
|
+
|
20
|
+
* camelize string fields to match sym behavior ([8f0382b](https://github.com/Gusto/apollo-federation-ruby/commit/8f0382b346d2cde5be252138275d67373b36acd7))
|
21
|
+
|
22
|
+
|
23
|
+
### BREAKING CHANGES
|
24
|
+
|
25
|
+
* string fields will be camelized by default rather than passed as is.
|
26
|
+
|
1
27
|
## [2.2.4](https://github.com/Gusto/apollo-federation-ruby/compare/v2.2.3...v2.2.4) (2022-04-01)
|
2
28
|
|
3
29
|
|
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:
|
@@ -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,31 +7,78 @@ 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',
|
17
36
|
arguments: [
|
18
37
|
name: 'fields',
|
19
|
-
values: ApolloFederation::FieldSetSerializer.serialize(
|
38
|
+
values: ApolloFederation::FieldSetSerializer.serialize(
|
39
|
+
requires[:fields],
|
40
|
+
camelize: requires.fetch(:camelize, true),
|
41
|
+
),
|
20
42
|
],
|
21
43
|
)
|
22
44
|
end
|
45
|
+
|
23
46
|
if provides
|
24
47
|
add_directive(
|
25
48
|
name: 'provides',
|
26
49
|
arguments: [
|
27
50
|
name: 'fields',
|
28
|
-
values: ApolloFederation::FieldSetSerializer.serialize(
|
51
|
+
values: ApolloFederation::FieldSetSerializer.serialize(
|
52
|
+
provides[:fields],
|
53
|
+
camelize: provides.fetch(:camelize, true),
|
54
|
+
),
|
29
55
|
],
|
30
56
|
)
|
31
57
|
end
|
32
58
|
|
33
|
-
|
34
|
-
|
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
|
35
82
|
end
|
36
83
|
end
|
37
84
|
end
|
@@ -6,20 +6,18 @@ module ApolloFederation
|
|
6
6
|
module FieldSetSerializer
|
7
7
|
extend self
|
8
8
|
|
9
|
-
def serialize(fields)
|
9
|
+
def serialize(fields, camelize: true)
|
10
10
|
case fields
|
11
11
|
when Hash
|
12
12
|
fields.map do |field, nested_selections|
|
13
|
-
"#{camelize(field)} { #{serialize(nested_selections)} }"
|
13
|
+
"#{camelize(field, camelize)} { #{serialize(nested_selections, camelize: camelize)} }"
|
14
14
|
end.join(' ')
|
15
15
|
when Array
|
16
16
|
fields.map do |field|
|
17
|
-
serialize(field)
|
17
|
+
serialize(field, camelize: camelize)
|
18
18
|
end.join(' ')
|
19
|
-
when String
|
20
|
-
fields
|
21
|
-
when Symbol
|
22
|
-
camelize(fields)
|
19
|
+
when Symbol, String
|
20
|
+
camelize(fields, camelize)
|
23
21
|
else
|
24
22
|
raise ArgumentError, "Unexpected field set type: #{fields.class}"
|
25
23
|
end
|
@@ -27,8 +25,8 @@ module ApolloFederation
|
|
27
25
|
|
28
26
|
private
|
29
27
|
|
30
|
-
def camelize(field)
|
31
|
-
GraphQL::Schema::Member::BuildType.camelize(field.to_s)
|
28
|
+
def camelize(field, camelize)
|
29
|
+
camelize ? GraphQL::Schema::Member::BuildType.camelize(field.to_s) : field.to_s
|
32
30
|
end
|
33
31
|
end
|
34
32
|
end
|
@@ -18,12 +18,16 @@ module ApolloFederation
|
|
18
18
|
add_directive(name: 'extends')
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def inaccessible
|
22
|
+
add_directive(name: 'inaccessible')
|
23
|
+
end
|
24
|
+
|
25
|
+
def key(fields:, camelize: true)
|
22
26
|
add_directive(
|
23
27
|
name: 'key',
|
24
28
|
arguments: [
|
25
29
|
name: 'fields',
|
26
|
-
values: ApolloFederation::FieldSetSerializer.serialize(fields),
|
30
|
+
values: ApolloFederation::FieldSetSerializer.serialize(fields, camelize: camelize),
|
27
31
|
],
|
28
32
|
)
|
29
33
|
end
|
@@ -16,12 +16,20 @@ module ApolloFederation
|
|
16
16
|
add_directive(name: 'extends')
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
19
|
+
def shareable
|
20
|
+
add_directive(name: 'shareable')
|
21
|
+
end
|
22
|
+
|
23
|
+
def inaccessible
|
24
|
+
add_directive(name: 'inaccessible')
|
25
|
+
end
|
26
|
+
|
27
|
+
def key(fields:, camelize: true)
|
20
28
|
add_directive(
|
21
29
|
name: 'key',
|
22
30
|
arguments: [
|
23
31
|
name: 'fields',
|
24
|
-
values: ApolloFederation::FieldSetSerializer.serialize(fields),
|
32
|
+
values: ApolloFederation::FieldSetSerializer.serialize(fields, camelize: camelize),
|
25
33
|
],
|
26
34
|
)
|
27
35
|
end
|
@@ -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:
|
4
|
+
version: 3.2.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-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: graphql
|