elasticgraph-apollo 0.18.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/apollo_tests_implementation/Dockerfile +66 -0
- data/apollo_tests_implementation/Gemfile +27 -0
- data/apollo_tests_implementation/Rakefile +22 -0
- data/apollo_tests_implementation/config/products_schema.rb +173 -0
- data/apollo_tests_implementation/config/settings.yaml +34 -0
- data/apollo_tests_implementation/config.ru +122 -0
- data/apollo_tests_implementation/docker-compose.yaml +18 -0
- data/apollo_tests_implementation/lib/test_implementation_extension.rb +58 -0
- data/apollo_tests_implementation/wait_for_datastore.sh +17 -0
- data/elasticgraph-apollo.gemspec +27 -0
- data/lib/elastic_graph/apollo/graphql/engine_extension.rb +52 -0
- data/lib/elastic_graph/apollo/graphql/entities_field_resolver.rb +305 -0
- data/lib/elastic_graph/apollo/graphql/http_endpoint_extension.rb +45 -0
- data/lib/elastic_graph/apollo/graphql/service_field_resolver.rb +30 -0
- data/lib/elastic_graph/apollo/schema_definition/api_extension.rb +385 -0
- data/lib/elastic_graph/apollo/schema_definition/apollo_directives.rb +119 -0
- data/lib/elastic_graph/apollo/schema_definition/argument_extension.rb +20 -0
- data/lib/elastic_graph/apollo/schema_definition/entity_type_extension.rb +30 -0
- data/lib/elastic_graph/apollo/schema_definition/enum_type_extension.rb +23 -0
- data/lib/elastic_graph/apollo/schema_definition/enum_value_extension.rb +20 -0
- data/lib/elastic_graph/apollo/schema_definition/factory_extension.rb +104 -0
- data/lib/elastic_graph/apollo/schema_definition/field_extension.rb +59 -0
- data/lib/elastic_graph/apollo/schema_definition/graphql_sdl_enumerator_extension.rb +69 -0
- data/lib/elastic_graph/apollo/schema_definition/input_type_extension.rb +20 -0
- data/lib/elastic_graph/apollo/schema_definition/interface_type_extension.rb +25 -0
- data/lib/elastic_graph/apollo/schema_definition/object_type_extension.rb +28 -0
- data/lib/elastic_graph/apollo/schema_definition/scalar_type_extension.rb +23 -0
- data/lib/elastic_graph/apollo/schema_definition/state_extension.rb +23 -0
- data/lib/elastic_graph/apollo/schema_definition/union_type_extension.rb +20 -0
- data/script/boot_eg_apollo_implementation +22 -0
- data/script/export_docker_env_vars.sh +15 -0
- data/script/test_compatibility +54 -0
- metadata +472 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d47ce5fd25c5cc7a7f8d2f0b366b7f3831155283af52c20b1853a84249dd2c9b
|
4
|
+
data.tar.gz: cac5ed0af92ae555317bb208d7cdf4599421bccc4ebaa7db18899fb8621dceb2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a547df1c78be131ad4799e475d9752569ac992459d3129b9cd3dfbfe2f529ecd3cd023032e33104c25c5bddeb623858b63d7e736f91dc54dd5ce54b05f68f83a
|
7
|
+
data.tar.gz: 182ee7cbc60949ee96c8c9055b65ed370b534355b64e54de6d240cf8a52f9c2778eac6e24fa1d606cdc176ba7eb1c0d7174a54b9d3e4de3f9413c51299d7fb09
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Block, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# ElasticGraph::Apollo
|
2
|
+
|
3
|
+
Implements the [Apollo Federation Subgraph Spec](https://www.apollographql.com/docs/federation/subgraph-spec/),
|
4
|
+
allowing an ElasticGraph application to be plugged into an Apollo-powered GraphQL server as a subgraph.
|
5
|
+
|
6
|
+
Note: this library only supports the v2 Federation specification.
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
First, add `elasticgraph-apollo` to your `Gemfile`:
|
11
|
+
|
12
|
+
``` ruby
|
13
|
+
gem "elasticgraph-apollo"
|
14
|
+
```
|
15
|
+
|
16
|
+
Finally, update your ElasticGraph schema artifact rake tasks in your `Rakefile`
|
17
|
+
so that `ElasticGraph::GraphQL::Apollo::SchemaDefinition::APIExtension` is
|
18
|
+
passed as one of the `extension_modules`:
|
19
|
+
|
20
|
+
``` ruby
|
21
|
+
require "elastic_graph/schema_definition/rake_tasks"
|
22
|
+
require "elastic_graph/apollo/schema_definition/api_extension"
|
23
|
+
|
24
|
+
ElasticGraph::SchemaDefinition::RakeTasks.new(
|
25
|
+
schema_element_name_form: :snake_case,
|
26
|
+
index_document_sizes: true,
|
27
|
+
path_to_schema: "config/schema.rb",
|
28
|
+
schema_artifacts_directory: artifacts_dir,
|
29
|
+
extension_modules: [ElasticGraph::Apollo::SchemaDefinition::APIExtension]
|
30
|
+
)
|
31
|
+
```
|
32
|
+
|
33
|
+
That's it!
|
34
|
+
|
35
|
+
## Federation Version Support
|
36
|
+
|
37
|
+
This library supports multiple versions of Apollo federation. As of Jan. 2024, it supports:
|
38
|
+
|
39
|
+
* v2.0
|
40
|
+
* v2.3
|
41
|
+
* v2.5
|
42
|
+
* v2.6
|
43
|
+
|
44
|
+
By default, the newest version is targeted. If you need an older version (e.g. because your organization is
|
45
|
+
running an older Apollo version), you can configure it in your schema definition with:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
schema.target_apollo_federation_version "2.3"
|
49
|
+
```
|
50
|
+
|
51
|
+
## Testing Notes
|
52
|
+
|
53
|
+
This project uses https://github.com/apollographql/apollo-federation-subgraph-compatibility
|
54
|
+
to verify compatibility with Apollo. Things to note:
|
55
|
+
|
56
|
+
- Run `elasticgraph-apollo/script/test_compatibility` to run the compatibility tests (the CI build runs this).
|
57
|
+
- Run `elasticgraph-apollo/script/boot_eg_apollo_implementation` to boot the ElasticGraph compatibility test implementation (can be useful for debugging `test_compatibility` failures).
|
58
|
+
- These scripts require some additional dependencies to be installed (such as `docker`, `node`, and `npm`).
|
59
|
+
- To get that to pass locally on my Mac, I had to enable the `Use Docker Compose V2` flag in Docker Desktop (under "Preferences -> General"). Without that checked, I got errors like this:
|
60
|
+
|
61
|
+
```
|
62
|
+
ERROR: for apollo-federation-subgraph-compatibility_router_1 Cannot start service router: OCI runtime create failed: container_linux.go:380: starting container process caused: process_linux.go:545: container init caused: rootfs_linux.go:76: mounting "/host_mnt/Users/myron/Development/sq-elasticgraph-ruby/elasticgraph-apollo/vendor/apollo-federation-subgraph-compatibility/supergraph.graphql" to rootfs at "/etc/config/supergraph.graphql" caused: mount through procfd: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
|
63
|
+
```
|
@@ -0,0 +1,66 @@
|
|
1
|
+
ARG RUBY_VERSION
|
2
|
+
FROM ruby:${RUBY_VERSION}
|
3
|
+
|
4
|
+
ARG TARGET_APOLLO_FEDERATION_VERSION
|
5
|
+
|
6
|
+
WORKDIR /web
|
7
|
+
|
8
|
+
# Each of the elasticgraph gems this implementation depends on must be
|
9
|
+
# copied into the container so it's available for inclusion in the bundle.
|
10
|
+
# Note: we've observed that hidden files (like .rspec) are not copied by COPY.
|
11
|
+
# gemspec_helper enforces the presence of `.rspec`/`.yardopts`, so we have to copy them.
|
12
|
+
COPY elasticgraph-admin /web/elasticgraph-admin
|
13
|
+
COPY elasticgraph-admin/.rspec /web/elasticgraph-admin/.rspec
|
14
|
+
COPY elasticgraph-admin/.yardopts /web/elasticgraph-admin/.yardopts
|
15
|
+
|
16
|
+
COPY elasticgraph-apollo /web/elasticgraph-apollo
|
17
|
+
COPY elasticgraph-apollo/.rspec /web/elasticgraph-apollo/.rspec
|
18
|
+
COPY elasticgraph-apollo/.yardopts /web/elasticgraph-apollo/.yardopts
|
19
|
+
|
20
|
+
COPY elasticgraph-datastore_core /web/elasticgraph-datastore_core
|
21
|
+
COPY elasticgraph-datastore_core/.rspec /web/elasticgraph-datastore_core/.rspec
|
22
|
+
COPY elasticgraph-datastore_core/.yardopts /web/elasticgraph-datastore_core/.yardopts
|
23
|
+
|
24
|
+
COPY elasticgraph-elasticsearch /web/elasticgraph-elasticsearch
|
25
|
+
COPY elasticgraph-elasticsearch/.rspec /web/elasticgraph-elasticsearch/.rspec
|
26
|
+
COPY elasticgraph-elasticsearch/.yardopts /web/elasticgraph-elasticsearch/.yardopts
|
27
|
+
|
28
|
+
COPY elasticgraph-graphql /web/elasticgraph-graphql
|
29
|
+
COPY elasticgraph-graphql/.rspec /web/elasticgraph-graphql/.rspec
|
30
|
+
COPY elasticgraph-graphql/.yardopts /web/elasticgraph-graphql/.yardopts
|
31
|
+
|
32
|
+
COPY elasticgraph-indexer /web/elasticgraph-indexer
|
33
|
+
COPY elasticgraph-indexer/.rspec /web/elasticgraph-indexer/.rspec
|
34
|
+
COPY elasticgraph-indexer/.yardopts /web/elasticgraph-indexer/.yardopts
|
35
|
+
|
36
|
+
COPY elasticgraph-json_schema /web/elasticgraph-json_schema
|
37
|
+
COPY elasticgraph-json_schema/.rspec /web/elasticgraph-json_schema/.rspec
|
38
|
+
COPY elasticgraph-json_schema/.yardopts /web/elasticgraph-json_schema/.yardopts
|
39
|
+
|
40
|
+
COPY elasticgraph-rack /web/elasticgraph-rack
|
41
|
+
COPY elasticgraph-rack/.rspec /web/elasticgraph-rack/.rspec
|
42
|
+
COPY elasticgraph-rack/.yardopts /web/elasticgraph-rack/.yardopts
|
43
|
+
|
44
|
+
COPY elasticgraph-schema_artifacts /web/elasticgraph-schema_artifacts
|
45
|
+
COPY elasticgraph-schema_artifacts/.rspec /web/elasticgraph-schema_artifacts/.rspec
|
46
|
+
COPY elasticgraph-schema_artifacts/.yardopts /web/elasticgraph-schema_artifacts/.yardopts
|
47
|
+
|
48
|
+
COPY elasticgraph-schema_definition /web/elasticgraph-schema_definition
|
49
|
+
COPY elasticgraph-schema_definition/.rspec /web/elasticgraph-schema_definition/.rspec
|
50
|
+
COPY elasticgraph-schema_definition/.yardopts /web/elasticgraph-schema_definition/.yardopts
|
51
|
+
|
52
|
+
COPY elasticgraph-support /web/elasticgraph-support
|
53
|
+
COPY elasticgraph-support/.rspec /web/elasticgraph-support/.rspec
|
54
|
+
COPY elasticgraph-support/.yardopts /web/elasticgraph-support/.yardopts
|
55
|
+
|
56
|
+
# We also have to copy the implementation files (config, schema, etc) as well.
|
57
|
+
COPY elasticgraph-apollo/apollo_tests_implementation /web/
|
58
|
+
|
59
|
+
COPY gemspec_helper.rb /web/gemspec_helper.rb
|
60
|
+
|
61
|
+
# We need to install the bundle and generate our schema artifacts.
|
62
|
+
RUN bundle install
|
63
|
+
RUN bundle exec rake schema_artifacts:dump TARGET_APOLLO_FEDERATION_VERSION=${TARGET_APOLLO_FEDERATION_VERSION}
|
64
|
+
|
65
|
+
# Finally we can boot the app!
|
66
|
+
CMD ["bundle", "exec", "rackup", "--host", "0.0.0.0", "--port", "4001"]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
source "https://rubygems.org"
|
10
|
+
|
11
|
+
%w[
|
12
|
+
admin
|
13
|
+
apollo
|
14
|
+
datastore_core
|
15
|
+
elasticsearch
|
16
|
+
graphql
|
17
|
+
indexer
|
18
|
+
json_schema
|
19
|
+
rack
|
20
|
+
schema_artifacts
|
21
|
+
schema_definition
|
22
|
+
support
|
23
|
+
].each do |suffix|
|
24
|
+
gem "elasticgraph-#{suffix}", path: "elasticgraph-#{suffix}"
|
25
|
+
end
|
26
|
+
|
27
|
+
gem "rackup", "~> 2.1"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/schema_definition/rake_tasks"
|
10
|
+
require "elastic_graph/apollo/schema_definition/api_extension"
|
11
|
+
require "pathname"
|
12
|
+
|
13
|
+
project_root = Pathname.new(__dir__)
|
14
|
+
|
15
|
+
ElasticGraph::SchemaDefinition::RakeTasks.new(
|
16
|
+
schema_element_name_form: :camelCase,
|
17
|
+
index_document_sizes: false,
|
18
|
+
path_to_schema: project_root / "config/products_schema.rb",
|
19
|
+
schema_artifacts_directory: project_root / "config/schema/artifacts",
|
20
|
+
extension_modules: [ElasticGraph::Apollo::SchemaDefinition::APIExtension],
|
21
|
+
enforce_json_schema_version: false
|
22
|
+
)
|
@@ -0,0 +1,173 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
module ApolloTestImpl
|
10
|
+
module GraphQLSDLEnumeratorExtension
|
11
|
+
# The `apollo-federation-subgraph-compatibility` project requires[^1] that each tested implementation provide
|
12
|
+
# specific `Query` fields:
|
13
|
+
#
|
14
|
+
# ```graphql
|
15
|
+
# type Query {
|
16
|
+
# product(id: ID!): Product
|
17
|
+
# deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead")
|
18
|
+
# }
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# ElasticGraph automatically provides plural fields for our indexed types (e.g. `products` and `deprecatedProducts`).
|
22
|
+
# For the Apollo tests we need to additionally provide the two fields above. This hooks into the generation of the
|
23
|
+
# `Query` type to add the required fields.
|
24
|
+
#
|
25
|
+
# [^1]: https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/2.0.0/COMPATIBILITY.md#products-schema-to-be-implemented-by-library-maintainers
|
26
|
+
def root_query_type
|
27
|
+
super.tap do |type|
|
28
|
+
type.field "product", "Product" do |f|
|
29
|
+
f.argument "id", "ID!"
|
30
|
+
end
|
31
|
+
|
32
|
+
type.field "deprecatedProduct", "DeprecatedProduct" do |f|
|
33
|
+
f.argument "sku", "String!"
|
34
|
+
f.argument "package", "String!"
|
35
|
+
f.directive "deprecated", reason: "Use product query instead"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module SchemaDefFactoryExtension
|
42
|
+
def new_graphql_sdl_enumerator(all_types_except_root_query_type)
|
43
|
+
super(all_types_except_root_query_type).tap do |enum|
|
44
|
+
enum.extend GraphQLSDLEnumeratorExtension
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
federation_version = ENV["TARGET_APOLLO_FEDERATION_VERSION"]
|
50
|
+
|
51
|
+
# Note: this includes many "manual" schema elements (directives, raw SDL, etc) that the
|
52
|
+
# `elasticgraph-apollo` library will generate on our behalf in the future. For now, this
|
53
|
+
# includes all these schema elements just to make it as close as possible to an apollo
|
54
|
+
# compatible schema without further changes to elasticgraph-apollo.
|
55
|
+
#
|
56
|
+
# https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/2.0.0/COMPATIBILITY.md#products-schema-to-be-implemented-by-library-maintainers
|
57
|
+
ElasticGraph.define_schema do |schema|
|
58
|
+
schema.factory.extend SchemaDefFactoryExtension
|
59
|
+
|
60
|
+
schema.json_schema_version 1
|
61
|
+
schema.target_apollo_federation_version(federation_version) if federation_version
|
62
|
+
|
63
|
+
unless federation_version == "2.0"
|
64
|
+
schema.raw_sdl <<~EOS
|
65
|
+
extend schema
|
66
|
+
@link(url: "https://myspecs.dev/myCustomDirective/v1.0", import: ["@custom"])
|
67
|
+
@composeDirective(name: "@custom")
|
68
|
+
|
69
|
+
directive @custom on OBJECT
|
70
|
+
EOS
|
71
|
+
end
|
72
|
+
|
73
|
+
schema.object_type "Product" do |t|
|
74
|
+
t.directive "custom" unless federation_version == "2.0"
|
75
|
+
t.apollo_key fields: "sku package"
|
76
|
+
t.apollo_key fields: "sku variation { id }"
|
77
|
+
|
78
|
+
t.field "id", "ID!"
|
79
|
+
t.field "sku", "String"
|
80
|
+
t.field "package", "String"
|
81
|
+
t.field "variation", "ProductVariation"
|
82
|
+
t.field "dimensions", "ProductDimension"
|
83
|
+
t.field "createdBy", "User" do |f|
|
84
|
+
f.apollo_provides fields: "totalProductsCreated"
|
85
|
+
end
|
86
|
+
t.field "notes", "String" do |f|
|
87
|
+
f.tag_with "internal"
|
88
|
+
end
|
89
|
+
t.field "research", "[ProductResearch!]!" do |f|
|
90
|
+
f.mapping type: "object"
|
91
|
+
end
|
92
|
+
|
93
|
+
t.index "products"
|
94
|
+
end
|
95
|
+
|
96
|
+
schema.object_type "DeprecatedProduct" do |t|
|
97
|
+
t.apollo_key fields: "sku package"
|
98
|
+
t.field "id", "ID!", indexing_only: true
|
99
|
+
t.field "sku", "String!"
|
100
|
+
t.field "package", "String!"
|
101
|
+
t.field "reason", "String"
|
102
|
+
t.field "createdBy", "User"
|
103
|
+
|
104
|
+
t.index "deprecated_products"
|
105
|
+
end
|
106
|
+
|
107
|
+
schema.object_type "ProductVariation" do |t|
|
108
|
+
t.field "id", "ID!"
|
109
|
+
end
|
110
|
+
|
111
|
+
schema.object_type "ProductResearch" do |t|
|
112
|
+
t.apollo_key fields: "study { caseNumber }"
|
113
|
+
t.field "id", "ID!", indexing_only: true
|
114
|
+
t.field "study", "CaseStudy!"
|
115
|
+
t.field "outcome", "String"
|
116
|
+
|
117
|
+
t.index "product_research"
|
118
|
+
end
|
119
|
+
|
120
|
+
schema.object_type "CaseStudy" do |t|
|
121
|
+
t.field "caseNumber", "ID!"
|
122
|
+
t.field "description", "String"
|
123
|
+
end
|
124
|
+
|
125
|
+
schema.object_type "ProductDimension" do |t|
|
126
|
+
t.apollo_shareable
|
127
|
+
t.field "size", "String"
|
128
|
+
t.field "weight", "Float"
|
129
|
+
t.field "unit", "String" do |f|
|
130
|
+
f.apollo_inaccessible
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
schema.object_type "User" do |t|
|
135
|
+
t.apollo_extends
|
136
|
+
t.apollo_key fields: "email"
|
137
|
+
t.field "id", "ID!", indexing_only: true
|
138
|
+
|
139
|
+
t.field "averageProductsCreatedPerYear", "Int" do |f|
|
140
|
+
f.apollo_requires fields: "totalProductsCreated yearsOfEmployment"
|
141
|
+
end
|
142
|
+
|
143
|
+
t.field "email", "ID!" do |f|
|
144
|
+
f.apollo_external
|
145
|
+
end
|
146
|
+
|
147
|
+
t.field "name", "String" do |f|
|
148
|
+
f.apollo_override from: "users"
|
149
|
+
end
|
150
|
+
|
151
|
+
t.field "totalProductsCreated", "Int" do |f|
|
152
|
+
f.apollo_external
|
153
|
+
end
|
154
|
+
|
155
|
+
t.field "yearsOfEmployment", "Int!" do |f|
|
156
|
+
f.apollo_external
|
157
|
+
end
|
158
|
+
|
159
|
+
t.index "users"
|
160
|
+
end
|
161
|
+
|
162
|
+
unless federation_version == "2.0"
|
163
|
+
schema.object_type "Inventory" do |t|
|
164
|
+
t.apollo_interface_object
|
165
|
+
t.field "id", "ID!"
|
166
|
+
t.field "deprecatedProducts", "[DeprecatedProduct!]!" do |f|
|
167
|
+
f.mapping type: "object"
|
168
|
+
end
|
169
|
+
t.index "inventory"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
datastore:
|
2
|
+
client_faraday_adapter:
|
3
|
+
name: net_http
|
4
|
+
clusters:
|
5
|
+
main:
|
6
|
+
url: http://elasticsearch:9200
|
7
|
+
backend: elasticsearch
|
8
|
+
settings: {}
|
9
|
+
index_definitions:
|
10
|
+
products: &standard_index_settings
|
11
|
+
query_cluster: "main"
|
12
|
+
index_into_clusters: ["main"]
|
13
|
+
ignore_routing_values: []
|
14
|
+
custom_timestamp_ranges: []
|
15
|
+
setting_overrides: {}
|
16
|
+
setting_overrides_by_timestamp: {}
|
17
|
+
deprecated_products: *standard_index_settings
|
18
|
+
product_research: *standard_index_settings
|
19
|
+
users: *standard_index_settings
|
20
|
+
inventory: *standard_index_settings
|
21
|
+
log_traffic: true
|
22
|
+
max_client_retries: 3
|
23
|
+
logger:
|
24
|
+
device: stdout
|
25
|
+
indexer:
|
26
|
+
latency_slo_thresholds_by_timestamp_in_ms: {}
|
27
|
+
graphql:
|
28
|
+
default_page_size: 50
|
29
|
+
max_page_size: 500
|
30
|
+
extension_modules:
|
31
|
+
- require_path: ./lib/test_implementation_extension
|
32
|
+
extension_name: ApolloTestImplementationExtension
|
33
|
+
schema_artifacts:
|
34
|
+
directory: config/schema/artifacts
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require "elastic_graph/admin"
|
10
|
+
require "elastic_graph/graphql"
|
11
|
+
require "elastic_graph/indexer"
|
12
|
+
require "elastic_graph/rack/graphiql"
|
13
|
+
require "elastic_graph/indexer/test_support/converters"
|
14
|
+
|
15
|
+
admin = ElasticGraph::Admin.from_yaml_file("config/settings.yaml")
|
16
|
+
graphql = ElasticGraph::GraphQL.from_yaml_file("config/settings.yaml")
|
17
|
+
indexer = ElasticGraph::Indexer.from_yaml_file("config/settings.yaml")
|
18
|
+
|
19
|
+
admin.cluster_configurator.configure_cluster($stdout)
|
20
|
+
|
21
|
+
# Example records expected by the apollo-federation-subgraph-compatibility test suite. based on:
|
22
|
+
# https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/2.1.0/COMPATIBILITY.md#expected-data-sets
|
23
|
+
dimension = {
|
24
|
+
size: "small",
|
25
|
+
weight: 1,
|
26
|
+
unit: "kg"
|
27
|
+
}
|
28
|
+
|
29
|
+
user = {
|
30
|
+
id: "1",
|
31
|
+
averageProductsCreatedPerYear: 133,
|
32
|
+
email: "support@apollographql.com",
|
33
|
+
name: "Jane Smith",
|
34
|
+
totalProductsCreated: 1337,
|
35
|
+
yearsOfEmployment: 10
|
36
|
+
}
|
37
|
+
|
38
|
+
deprecated_product = {
|
39
|
+
id: "1",
|
40
|
+
sku: "apollo-federation-v1",
|
41
|
+
package: "@apollo/federation-v1",
|
42
|
+
reason: "Migrate to Federation V2",
|
43
|
+
createdBy: user
|
44
|
+
}
|
45
|
+
|
46
|
+
products_research = [
|
47
|
+
{
|
48
|
+
id: "1",
|
49
|
+
study: {
|
50
|
+
caseNumber: "1234",
|
51
|
+
description: "Federation Study"
|
52
|
+
},
|
53
|
+
outcome: nil
|
54
|
+
},
|
55
|
+
{
|
56
|
+
id: "2",
|
57
|
+
study: {
|
58
|
+
caseNumber: "1235",
|
59
|
+
description: "Studio Study"
|
60
|
+
},
|
61
|
+
outcome: nil
|
62
|
+
}
|
63
|
+
]
|
64
|
+
|
65
|
+
products = [
|
66
|
+
{
|
67
|
+
id: "apollo-federation",
|
68
|
+
sku: "federation",
|
69
|
+
package: "@apollo/federation",
|
70
|
+
variation: {
|
71
|
+
id: "OSS"
|
72
|
+
},
|
73
|
+
dimensions: dimension,
|
74
|
+
research: [products_research[0]],
|
75
|
+
createdBy: user,
|
76
|
+
notes: nil
|
77
|
+
},
|
78
|
+
{
|
79
|
+
id: "apollo-studio",
|
80
|
+
sku: "studio",
|
81
|
+
package: "",
|
82
|
+
variation: {
|
83
|
+
id: "platform"
|
84
|
+
},
|
85
|
+
dimensions: dimension,
|
86
|
+
research: [products_research[1]],
|
87
|
+
createdBy: user,
|
88
|
+
notes: nil
|
89
|
+
}
|
90
|
+
]
|
91
|
+
|
92
|
+
inventory = {
|
93
|
+
id: "apollo-oss",
|
94
|
+
deprecatedProducts: [deprecated_product]
|
95
|
+
}
|
96
|
+
|
97
|
+
records_by_type = {
|
98
|
+
"Product" => products,
|
99
|
+
"DeprecatedProduct" => [deprecated_product],
|
100
|
+
"ProductResearch" => products_research,
|
101
|
+
"User" => [user],
|
102
|
+
"Inventory" => [inventory]
|
103
|
+
}
|
104
|
+
|
105
|
+
events = records_by_type.flat_map do |type_name, records|
|
106
|
+
records = records.map.with_index do |record, index|
|
107
|
+
{
|
108
|
+
__typename: type_name,
|
109
|
+
__version: 1,
|
110
|
+
__json_schema_version: 1
|
111
|
+
}.merge(record)
|
112
|
+
end
|
113
|
+
|
114
|
+
ElasticGraph::Indexer::TestSupport::Converters.upsert_events_for_records(records)
|
115
|
+
end
|
116
|
+
|
117
|
+
indexer.processor.process(events, refresh_indices: true)
|
118
|
+
|
119
|
+
puts "Elasticsearch bootstrapping done. Booting the GraphQL server."
|
120
|
+
|
121
|
+
use Rack::ShowExceptions
|
122
|
+
run ElasticGraph::Rack::GraphiQL.new(graphql)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
include:
|
2
|
+
- ../../elasticgraph-local/lib/elastic_graph/local/elasticsearch/docker-compose.yaml
|
3
|
+
services:
|
4
|
+
products:
|
5
|
+
build:
|
6
|
+
context: ../..
|
7
|
+
dockerfile: elasticgraph-apollo/apollo_tests_implementation/Dockerfile
|
8
|
+
args:
|
9
|
+
TARGET_APOLLO_FEDERATION_VERSION: ${TARGET_APOLLO_FEDERATION_VERSION}
|
10
|
+
RUBY_VERSION: ${RUBY_VERSION}
|
11
|
+
ports:
|
12
|
+
- 4001:4001
|
13
|
+
depends_on:
|
14
|
+
- elasticsearch
|
15
|
+
command: ["./wait_for_datastore.sh", "elasticsearch:9200", "bundle", "exec", "rackup", "--host", "0.0.0.0", "--port", "4001"]
|
16
|
+
volumes:
|
17
|
+
data01:
|
18
|
+
driver: local
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
# The `apollo-federation-subgraph-compatibility` project requires that each tested
|
10
|
+
# implementation provide a `Query.product(id: ID!): Product` field. ElasticGraph provides
|
11
|
+
# `Query.products(...): ProductConnection!` automatically. To be able to pass the tests,
|
12
|
+
# we need to provide the `product` field, even though ElasticGraph doesn't natively provide
|
13
|
+
# it.
|
14
|
+
#
|
15
|
+
# This defines an extension that injects a custom resolver that supports the field.
|
16
|
+
module ApolloTestImplementationExtension
|
17
|
+
def graphql_resolvers
|
18
|
+
@graphql_resolvers ||= [product_field_resolver] + super
|
19
|
+
end
|
20
|
+
|
21
|
+
def product_field_resolver
|
22
|
+
@product_field_resolver ||= ProductFieldResolver.new(
|
23
|
+
datastore_query_builder: datastore_query_builder,
|
24
|
+
product_index_def: datastore_core.index_definitions_by_name.fetch("products"),
|
25
|
+
datastore_router: datastore_search_router
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
class ProductFieldResolver
|
30
|
+
def initialize(datastore_query_builder:, product_index_def:, datastore_router:)
|
31
|
+
@datastore_query_builder = datastore_query_builder
|
32
|
+
@product_index_def = product_index_def
|
33
|
+
@datastore_router = datastore_router
|
34
|
+
end
|
35
|
+
|
36
|
+
def can_resolve?(field:, object:)
|
37
|
+
field.parent_type.name == :Query && field.name == :product
|
38
|
+
end
|
39
|
+
|
40
|
+
def resolve(field:, object:, args:, context:, lookahead:)
|
41
|
+
query = @datastore_query_builder.new_query(
|
42
|
+
search_index_definitions: [@product_index_def],
|
43
|
+
monotonic_clock_deadline: context[:monotonic_clock_deadline],
|
44
|
+
filter: {"id" => {"equalToAnyOf" => [args.fetch("id")]}},
|
45
|
+
individual_docs_needed: true,
|
46
|
+
requested_fields: %w[
|
47
|
+
id sku package notes
|
48
|
+
variation.id
|
49
|
+
dimensions.size dimensions.weight dimensions.unit
|
50
|
+
createdBy.averageProductsCreatedPerYear createdBy.email createdBy.name createdBy.totalProductsCreated createdBy.yearsOfEmployment
|
51
|
+
research.study.caseNumber research.study.description research.outcome
|
52
|
+
]
|
53
|
+
)
|
54
|
+
|
55
|
+
@datastore_router.msearch([query]).fetch(query).documents.first
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# Inspired by an example from the docker docks:
|
4
|
+
# https://docs.docker.com/compose/startup-order/
|
5
|
+
|
6
|
+
set -e
|
7
|
+
|
8
|
+
host="$1"
|
9
|
+
shift
|
10
|
+
|
11
|
+
until curl -f "$host"; do
|
12
|
+
>&2 echo "The datastore is unavailable - sleeping"
|
13
|
+
sleep 1
|
14
|
+
done
|
15
|
+
|
16
|
+
>&2 echo "The datastore is up - executing command"
|
17
|
+
exec "$@"
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Copyright 2024 Block, Inc.
|
2
|
+
#
|
3
|
+
# Use of this source code is governed by an MIT-style
|
4
|
+
# license that can be found in the LICENSE file or at
|
5
|
+
# https://opensource.org/licenses/MIT.
|
6
|
+
#
|
7
|
+
# frozen_string_literal: true
|
8
|
+
|
9
|
+
require_relative "../gemspec_helper"
|
10
|
+
|
11
|
+
ElasticGraphGemspecHelper.define_elasticgraph_gem(gemspec_file: __FILE__, category: :extension) do |spec, eg_version|
|
12
|
+
spec.summary = "An ElasticGraph extension that implements the Apollo federation spec."
|
13
|
+
|
14
|
+
spec.add_dependency "elasticgraph-graphql", eg_version
|
15
|
+
spec.add_dependency "elasticgraph-support", eg_version
|
16
|
+
spec.add_dependency "graphql", ">= 2.3.7", "< 2.4"
|
17
|
+
spec.add_dependency "apollo-federation", "~> 3.8"
|
18
|
+
|
19
|
+
# Note: technically, this is not purely a development dependency, but since `eg-schema_def`
|
20
|
+
# isn't intended to be used in production (or even included in a deployed bundle) we don't
|
21
|
+
# want to declare it as normal dependency here.
|
22
|
+
spec.add_development_dependency "elasticgraph-schema_definition", eg_version
|
23
|
+
spec.add_development_dependency "elasticgraph-admin", eg_version
|
24
|
+
spec.add_development_dependency "elasticgraph-elasticsearch", eg_version
|
25
|
+
spec.add_development_dependency "elasticgraph-opensearch", eg_version
|
26
|
+
spec.add_development_dependency "elasticgraph-indexer", eg_version
|
27
|
+
end
|