apollo-federation 3.10.1 → 3.10.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f380edb23cd987294131a8517dc4d08331ebbbde711192baf759598c2d5ad733
4
- data.tar.gz: ffee0d8e1d99f79ac7ba82f5f50a0d107e5b3a775ef8a9d6aff8e74f0896b221
3
+ metadata.gz: 0b6e50afd09ae68365aa079f13a4e53ad681628d8a537166985d4da3eb6ef6ce
4
+ data.tar.gz: 8af107ff7dd73927fd241ad852916924ffe131db58da81facb37c8f75c88c95d
5
5
  SHA512:
6
- metadata.gz: 70e9f855c9a6284d23e69e27c85f8b4d9d85a2e93ac328a134260f3eb7328f9f3629bed1fd0acc6965d9272cadb3d7b59fbf30f1039359ddcb074074d1a0c599
7
- data.tar.gz: 5d8bf20436400d80fa0f83f05aa37c3eb82d8525364ecc31e51b71ee16184cb5c8e3524ff236c001fd005191b5615ed38cbc2b2bb9ed10522c0892be99f6f5d8
6
+ metadata.gz: 742d3beea298bcac5bad03cd49181f587735d1a42e08d4fd1fb31b2ddcb5d948c30be2c6cbd24d453d8922e5992d9a225f314fb96ad6c5260369a86d84adb5ac
7
+ data.tar.gz: bc802e2a591d2c902c972f566362904b156054af8afe1800c1b861c1d2d062fbe552940f69d6814950c481fe06a839ed0e787c8edc49867dab90c1b288a0b28f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## [3.10.3](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.2...v3.10.3) (2025-10-20)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * random update to README.md to trigger semantic-release ([#310](https://github.com/Gusto/apollo-federation-ruby/issues/310)) ([bfaa10e](https://github.com/Gusto/apollo-federation-ruby/commit/bfaa10e85a7e85781f2ae0373d656b0fc66d13eb))
7
+
8
+
9
+ ### Reverts
10
+
11
+ * Revert "chore(release): 3.10.2 [skip ci]" (#309) ([a3937c6](https://github.com/Gusto/apollo-federation-ruby/commit/a3937c64f0ce9648edc10f74a80a4e825e01b4d4)), closes [#309](https://github.com/Gusto/apollo-federation-ruby/issues/309)
12
+
13
+ ## [3.10.5](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.4...v3.10.5) (2026-10-01)
14
+
15
+
16
+ ### Bug Fixes
17
+
18
+ * add environment: release to the Publish Gem job ([#323](https://github.com/Gusto/apollo-federation-ruby/issues/323)) ([abbe9c6](https://github.com/Gusto/apollo-federation-ruby/commit/abbe9c652bf4fcfd5a23c238981a91bc5ad47da1))
19
+
20
+ ## [3.10.4](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.3...v3.10.4) (2026-09-30)
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * authenticate release-please-action with a GitHub App token, not GITHUB_TOKEN ([#320](https://github.com/Gusto/apollo-federation-ruby/issues/320)) ([0231a15](https://github.com/Gusto/apollo-federation-ruby/commit/0231a1573253739573fa2a8b17aeb9a124e73728))
26
+ * Query._entities crashing under GraphQL::Execution::Next ([#317](https://github.com/Gusto/apollo-federation-ruby/issues/317)) ([4b869ba](https://github.com/Gusto/apollo-federation-ruby/commit/4b869ba7b4e5377cef0a08c8967386f38b6b7b97))
27
+ * regenerate Gemfile.lock on the release PR after version bumps ([#322](https://github.com/Gusto/apollo-federation-ruby/issues/322)) ([c6122dc](https://github.com/Gusto/apollo-federation-ruby/commit/c6122dcccb8d246642bc799f5b4e7fb8b749b84c))
28
+ * restore environment: release on the release-please job ([#321](https://github.com/Gusto/apollo-federation-ruby/issues/321)) ([61904d8](https://github.com/Gusto/apollo-federation-ruby/commit/61904d86023f14f6fbd661417e60ecc7ce166ec4))
29
+
1
30
  ## [3.10.1](https://github.com/Gusto/apollo-federation-ruby/compare/v3.10.0...v3.10.1) (2025-04-02)
2
31
 
3
32
 
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # apollo-federation
2
2
 
3
- [![CircleCI](https://circleci.com/gh/Gusto/apollo-federation-ruby/tree/main.svg?style=svg)](https://circleci.com/gh/Gusto/apollo-federation-ruby/tree/main)
3
+ [![CI](https://github.com/Gusto/apollo-federation-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/Gusto/apollo-federation-ruby/actions/workflows/ci.yml)
4
4
 
5
5
  This gem extends the [GraphQL Ruby](http://graphql-ruby.org/) gem to add support for creating an [Apollo Federation](https://www.apollographql.com/docs/apollo-server/federation/introduction/) schema.
6
6
 
7
+
7
8
  ## Installation
8
9
 
9
10
  Add this line to your application's Gemfile:
@@ -144,7 +145,9 @@ This will start up the gateway and serve it at http://localhost:5000.
144
145
 
145
146
  ## Usage
146
147
 
147
- The API is designed to mimic the API of [Apollo's federation library](https://www.apollographql.com/docs/apollo-server/federation/introduction/). It's best to read and understand the way federation works, in general, before attempting to use this library.
148
+ The API is designed to mimic the API of [Apollo's federation library](https://www.apollographql.com/docs/apollo-server/federation/introduction/).
149
+
150
+ It's best to read and understand the way federation works, in general, before attempting to use this library.
148
151
 
149
152
  ### Extending a type
150
153
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'graphql'
4
4
  require 'apollo-federation/any'
5
+ require 'apollo-federation/next_execution_support'
5
6
 
6
7
  module ApolloFederation
7
8
  module EntitiesField
@@ -20,80 +21,102 @@ module ApolloFederation
20
21
  possible_types(*possible_entities)
21
22
  end
22
23
 
23
- field(:_entities, [entity_type, null: true], null: false) do
24
+ # resolve_static so Next dispatches to resolve_entities_for_next, not root_value; a
25
+ # separate method from _entities since Next needs a fully-synced Array, not a Lazy.
26
+ if ApolloFederation::RESOLVE_STATIC_SUPPORTED
27
+ entities_field_options = { resolve_static: :resolve_entities_for_next }
28
+ else
29
+ entities_field_options = {}
30
+ end
31
+ field(:_entities, [entity_type, null: true], null: false, **entities_field_options) do
24
32
  argument :representations, [Any], required: true
25
33
  end
26
34
  end
27
- end
28
35
 
29
- def _entities(representations:)
30
- final_result = Array.new(representations.size)
31
- grouped_references_with_indices =
32
- representations
33
- .map
34
- .with_index { |r, i| [r, i] }
35
- .group_by { |(r, _i)| r[:__typename] }
36
-
37
- maybe_lazies = grouped_references_with_indices.map do |typename, references_with_indices|
38
- references = references_with_indices.map(&:first)
39
- indices = references_with_indices.map(&:last)
40
-
41
- # TODO: Use warden or schema?
42
- type = context.warden.get_type(typename)
43
- if type.nil? || type.kind != GraphQL::TypeKinds::OBJECT
44
- # TODO: Raise a specific error class?
45
- raise "The _entities resolver tried to load an entity for type \"#{typename}\"," \
46
- ' but no object type of that name was found in the schema'
47
- end
36
+ def _entities(context, representations:)
37
+ build_entities(context, representations)
38
+ end
48
39
 
49
- # TODO: What if the type is an interface?
50
- type_class = class_of_type(type)
40
+ def resolve_entities_for_next(context, representations:)
41
+ final_result = build_entities(context, representations).value
42
+ # Resolving the outer Lazy doesn't resolve each entry: a per-reference resolve_reference
43
+ # lazy value comes back wrapped in its own Lazy from the after_lazy call in build_entities.
44
+ final_result.map { |entry| entry.is_a?(GraphQL::Execution::Lazy) ? entry.value : entry }
45
+ end
46
+
47
+ private
48
+
49
+ def build_entities(context, representations)
50
+ final_result = Array.new(representations.size)
51
+ grouped_references_with_indices =
52
+ representations
53
+ .map
54
+ .with_index { |r, i| [r, i] }
55
+ .group_by { |(r, _i)| r[:__typename] }
56
+
57
+ maybe_lazies = grouped_references_with_indices.map do |typename, references_with_indices|
58
+ references = references_with_indices.map(&:first)
59
+ indices = references_with_indices.map(&:last)
60
+
61
+ # TODO: Use warden or schema?
62
+ type = context.warden.get_type(typename)
63
+ if type.nil? || type.kind != GraphQL::TypeKinds::OBJECT
64
+ # TODO: Raise a specific error class?
65
+ raise "The _entities resolver tried to load an entity for type \"#{typename}\"," \
66
+ ' but no object type of that name was found in the schema'
67
+ end
51
68
 
52
- if type_class.underscore_reference_keys
53
- references.map! do |reference|
54
- reference.transform_keys do |key|
55
- GraphQL::Schema::Member::BuildType.underscore(key.to_s).to_sym
69
+ # TODO: What if the type is an interface?
70
+ type_class = class_of_type(type)
71
+
72
+ if type_class.underscore_reference_keys
73
+ references.map! do |reference|
74
+ reference.transform_keys do |key|
75
+ GraphQL::Schema::Member::BuildType.underscore(key.to_s).to_sym
76
+ end
56
77
  end
57
78
  end
58
- end
59
79
 
60
- if type_class.respond_to?(:resolve_references)
61
- results = type_class.resolve_references(references, context)
62
- elsif type_class.respond_to?(:resolve_reference)
63
- results = references.map { |reference| type_class.resolve_reference(reference, context) }
64
- else
65
- results = references
66
- end
80
+ if type_class.respond_to?(:resolve_references)
81
+ results = type_class.resolve_references(references, context)
82
+ elsif type_class.respond_to?(:resolve_reference)
83
+ results = references.map { |reference| type_class.resolve_reference(reference, context) }
84
+ else
85
+ results = references
86
+ end
67
87
 
68
- context.schema.after_lazy(results) do |resolved_results|
69
- resolved_results.zip(indices).each do |result, i|
70
- final_result[i] = context.schema.after_lazy(result) do |resolved_value|
71
- # TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference
72
- # calls return the same object, it might not have the right type
73
- # Right now, apollo-federation just adds a __typename property to the result,
74
- # but I don't really like the idea of modifying the resolved object
75
- context[resolved_value] = type
76
- resolved_value
88
+ context.schema.after_lazy(results) do |resolved_results|
89
+ resolved_results.zip(indices).each do |result, i|
90
+ final_result[i] = context.schema.after_lazy(result) do |resolved_value|
91
+ # TODO: This isn't 100% correct: if (for some reason) 2 different resolve_reference
92
+ # calls return the same object, it might not have the right type
93
+ # Right now, apollo-federation just adds a __typename property to the result,
94
+ # but I don't really like the idea of modifying the resolved object
95
+ context[resolved_value] = type
96
+ resolved_value
97
+ end
77
98
  end
78
99
  end
79
100
  end
101
+
102
+ # Make sure we've resolved the outer level of lazies so we can return an array with a possibly lazy
103
+ # entry for each requested entity
104
+ GraphQL::Execution::Lazy.all(maybe_lazies).then do
105
+ final_result
106
+ end
80
107
  end
81
108
 
82
- # Make sure we've resolved the outer level of lazies so we can return an array with a possibly lazy
83
- # entry for each requested entity
84
- GraphQL::Execution::Lazy.all(maybe_lazies).then do
85
- final_result
109
+ def class_of_type(type)
110
+ if defined?(GraphQL::ObjectType) && type.is_a?(GraphQL::ObjectType)
111
+ type.metadata[:type_class]
112
+ else
113
+ type
114
+ end
86
115
  end
87
116
  end
88
117
 
89
- private
90
-
91
- def class_of_type(type)
92
- if defined?(GraphQL::ObjectType) && type.is_a?(GraphQL::ObjectType)
93
- type.metadata[:type_class]
94
- else
95
- type
96
- end
118
+ def _entities(representations:)
119
+ self.class._entities(context, representations: representations)
97
120
  end
98
121
  end
99
122
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql'
4
+
5
+ module ApolloFederation
6
+ # `resolve_static:` (and GraphQL::Execution::Next generally) doesn't exist on every
7
+ # graphql-ruby version this gem supports, so detect it via a capability the Next-era
8
+ # GraphQL::Schema::Field always defines, rather than assuming a minimum graphql-ruby version.
9
+ # Checking Field#initialize's own parameter list (an earlier version of this check) breaks
10
+ # under graphql-pro, which prepends a `(*args, streamable:, **kwargs)`-shaped `initialize` onto
11
+ # Field -- `instance_method(:initialize)` then reports *that* signature, not the one
12
+ # underneath, so the check silently reads as unsupported. `execution_mode` is a plain
13
+ # `attr_reader`, untouched by that prepend either way. Shared by any field this gem defines
14
+ # directly on the Query type (currently _entities and _service), since those are resolved
15
+ # against the wrapped Query object under classic but the (nil, by default) Query root_value
16
+ # under Next's default :direct_send -- resolve_static is what makes them agree.
17
+ RESOLVE_STATIC_SUPPORTED = GraphQL::Schema::Field.method_defined?(:execution_mode)
18
+ end
@@ -9,6 +9,7 @@ module ApolloFederation
9
9
  'directives, removes federation types, and includes rest of full schema after schema ' \
10
10
  'directives have been applied'
11
11
 
12
- field(:sdl, String, null: true)
12
+ # hash_key: so Next reads the { sdl: ... } Hash (see ServiceField#_service) directly.
13
+ field(:sdl, String, null: true, hash_key: :sdl)
13
14
  end
14
15
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'graphql'
4
4
  require 'apollo-federation/service'
5
+ require 'apollo-federation/next_execution_support'
5
6
 
6
7
  module ApolloFederation
7
8
  module ServiceField
@@ -13,13 +14,19 @@ module ApolloFederation
13
14
  extend GraphQL::Schema::Member::HasFields
14
15
 
15
16
  def define_service_field
16
- field(:_service, Service, null: false)
17
+ # resolve_static so Next dispatches to the class method below, not root_value.
18
+ service_field_options = ApolloFederation::RESOLVE_STATIC_SUPPORTED ? { resolve_static: true } : {}
19
+ field(:_service, Service, null: false, **service_field_options)
20
+ end
21
+
22
+ def _service(context)
23
+ schema_class = context.schema.is_a?(GraphQL::Schema) ? context.schema.class : context.schema
24
+ { sdl: schema_class.federation_sdl(context: context.to_h) }
17
25
  end
18
26
  end
19
27
 
20
28
  def _service
21
- schema_class = context.schema.is_a?(GraphQL::Schema) ? context.schema.class : context.schema
22
- { sdl: schema_class.federation_sdl(context: context.to_h) }
29
+ self.class._service(context)
23
30
  end
24
31
  end
25
32
  end
@@ -26,8 +26,10 @@
26
26
  #
27
27
  # </execute_query_lazy>
28
28
  #
29
- # # `execute_query_lazy` *always* fires, so it's a
30
- # # safe place to capture ending times of the full query.
29
+ # # In graphql-ruby < 2.5.12, `execute_query_lazy` *always* fires.
30
+ # # In graphql-ruby >= 2.5.12, `execute_query_lazy` only fires when there are lazy values.
31
+ # # We record end times in both `execute_multiplex` (as a fallback) and `execute_query_lazy`
32
+ # # (to capture the full execution time including lazy resolution when present).
31
33
  #
32
34
  # </execute_multiplex>
33
35
 
@@ -96,6 +98,12 @@ module ApolloFederation
96
98
 
97
99
  results = block.call
98
100
 
101
+ # Step 4.5:
102
+ # Record end times for all queries.
103
+ # This acts as a fallback for queries without lazy values.
104
+ # execute_query_lazy will overwrite these times if lazy values are present.
105
+ data.fetch(:multiplex).queries.each { |query| record_trace_end_time(query) }
106
+
99
107
  # Step 5
100
108
  # Attach the trace to the 'extensions' key of each result
101
109
  results.map { |result| attach_trace_to_result(result) }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ApolloFederation
4
- VERSION = '3.10.1'
4
+ VERSION = '3.10.5'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apollo-federation
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.1
4
+ version: 3.10.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Noa Elad
8
8
  - Rylan Collins
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-02 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -232,6 +232,7 @@ files:
232
232
  - lib/apollo-federation/has_directives.rb
233
233
  - lib/apollo-federation/input_object.rb
234
234
  - lib/apollo-federation/interface.rb
235
+ - lib/apollo-federation/next_execution_support.rb
235
236
  - lib/apollo-federation/object.rb
236
237
  - lib/apollo-federation/scalar.rb
237
238
  - lib/apollo-federation/schema.rb
@@ -267,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
267
268
  - !ruby/object:Gem::Version
268
269
  version: '0'
269
270
  requirements: []
270
- rubygems_version: 3.6.2
271
+ rubygems_version: 3.6.9
271
272
  specification_version: 4
272
273
  summary: A Ruby implementation of Apollo Federation
273
274
  test_files: []