Skip to content

Commit d979d6c

Browse files
committed
more stuff.
1 parent 4910316 commit d979d6c

File tree

6 files changed

+93
-92
lines changed

6 files changed

+93
-92
lines changed

docs/error_handling.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Failed stitching requests can be tricky to debug because it's not always obvious
44

55
### Supergraph errors
66

7-
When exceptions happen while executing requests within the stitching layer, they will be rescued by the stitching client and trigger an `on_error` hook. You should add your stack's error reporting here:
7+
When exceptions happen while executing requests within the stitching layer, they will be rescued by the stitching client and trigger an `on_error` hook. You can add your stack's error reporting here:
88

99
```ruby
1010
client = GraphQL::Stitching::Client.new(locations: { ... })
@@ -20,7 +20,7 @@ To modify the format of returned error messages that appear in [GraphQL errors](
2020
class MyClient < GraphQL::Stitching::Client
2121
def build_graphql_error(request, err)
2222
graphql_error = super(request, err)
23-
graphql_error["message"] << ". Contact support about Request ID #{request.context[:request_id]}"
23+
graphql_error["message"] << " Contact support about Request ID #{request.context[:request_id]}"
2424
graphql_error
2525
end
2626
end

lib/graphql/stitching/client.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ def execute(raw_query = nil, query: nil, variables: nil, operation_name: nil, co
5858

5959
load_plan(request)
6060
request.execute
61+
rescue GraphQL::ParseError, GraphQL::ExecutionError => e
62+
error_result(request, [e.to_h])
6163
rescue StandardError => e
6264
@on_error.call(request, e) if @on_error
6365
error_result(request, [build_graphql_error(request, e)])

lib/graphql/stitching/composer.rb

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,6 @@ module Stitching
1111
# representing various graph locations and merges them into one
1212
# combined Supergraph that is validated for integrity.
1313
class Composer
14-
# @api private
15-
class DefaultFormatter
16-
extend Formatter
17-
end
18-
1914
# @api private
2015
NO_DEFAULT_VALUE = begin
2116
t = Class.new(GraphQL::Schema::Object) do
@@ -58,7 +53,7 @@ def initialize(
5853
@mutation_name = mutation_name
5954
@subscription_name = subscription_name
6055
@root_entrypoints = root_entrypoints || {}
61-
@formatter = formatter || DefaultFormatter
56+
@formatter = formatter || Formatter::Default
6257

6358
@field_map = {}
6459
@resolver_map = {}
@@ -472,7 +467,7 @@ def build_merged_directives(type_name, members_by_location, owner, field_name: n
472467

473468
if (profiles = kwarg_values_by_name_location["profiles"])
474469
@visibility_profiles.merge(profiles.each_value.reduce(&:|))
475-
kwarg_formatter = DefaultFormatter
470+
kwarg_formatter = Formatter::Default
476471
end
477472
end
478473

lib/graphql/stitching/formatter.rb

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
module GraphQL
77
module Stitching
88
module Formatter
9+
class Default
10+
extend Formatter
11+
end
12+
913
class Info
1014
attr_reader :type_name, :field_name, :argument_name, :enum_value, :directive_name, :kwarg_name
1115

@@ -50,13 +54,8 @@ def merge_kwargs(values_by_location, info)
5054
end
5155
end
5256

53-
def build_graphql_error(request, err)
54-
case err
55-
when GraphQL::ParseError, GraphQL::ExecutionError
56-
err.to_h
57-
else
58-
{ "message" => "An unexpected error occured." }
59-
end
57+
def build_graphql_error(_request, _err)
58+
{ "message" => "An unexpected error occured." }
6059
end
6160
end
6261
end
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# frozen_string_literal: true
2+
3+
require "test_helper"
4+
require_relative "../../../schemas/example"
5+
6+
describe "GraphQL::Stitching::Client" do
7+
class MyClient < GraphQL::Stitching::Client
8+
def merge_descriptions(values_by_location, _info)
9+
values_by_location.values.join("/")
10+
end
11+
12+
def build_graphql_error(request, err)
13+
{ "message" => "Contact support about request #{request.context[:request_id]}." }
14+
end
15+
end
16+
17+
def test_client_acts_as_composition_formatter
18+
alpha = %|
19+
"""
20+
a
21+
"""
22+
type Query { a:Boolean }
23+
|
24+
bravo = %|
25+
"""
26+
b
27+
"""
28+
type Query { b:Boolean }
29+
|
30+
31+
client = MyClient.new(locations: {
32+
"alpha" => { schema: GraphQL::Schema.from_definition(alpha) },
33+
"bravo" => { schema: GraphQL::Schema.from_definition(bravo) },
34+
})
35+
36+
assert_equal "a/b", client.supergraph.schema.query.description
37+
end
38+
39+
def test_client_builds_graphql_errors
40+
client = MyClient.new(locations: {
41+
products: { schema: Schemas::Example::Products },
42+
})
43+
44+
result = client.execute(
45+
query: "query { invalidSelection }",
46+
context: { request_id: "R2d2c3P0" },
47+
validate: false
48+
)
49+
50+
expected_errors = [{
51+
"message" => "Contact support about request R2d2c3P0.",
52+
}]
53+
54+
assert_nil result["data"]
55+
assert_equal expected_errors, result["errors"]
56+
end
57+
58+
def test_client_from_definition_builds_specific_class
59+
alpha = %|
60+
type T { id:ID! a:String }
61+
type Query { a(id:ID!):T @stitch(key: "id") }
62+
|
63+
bravo = %|
64+
type T { id:ID! b:String }
65+
type Query { b(id:ID!):T @stitch(key: "id") }
66+
|
67+
68+
sdl = compose_definitions({ "alpha" => alpha, "bravo" => bravo }).to_definition
69+
client = MyClient.from_definition(sdl, executables: {
70+
"alpha" => Proc.new {},
71+
"bravo" => Proc.new {},
72+
})
73+
assert client.is_a?(MyClient)
74+
end
75+
end

test/graphql/stitching/client_test.rb renamed to test/graphql/stitching/client/client_test.rb

Lines changed: 6 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22

33
require "test_helper"
4-
require_relative "../../schemas/example"
4+
require_relative "../../../schemas/example"
55

66
describe "GraphQL::Stitching::Client" do
77
def setup_client
@@ -297,7 +297,7 @@ def test_caching_hooks_receive_request_context
297297
assert_equal context[:key], write_context
298298
end
299299

300-
def test_invalid_query
300+
def test_query_with_static_validation_errors
301301
client = GraphQL::Stitching::Client.new(locations: {
302302
products: {
303303
schema: Schemas::Example::Products,
@@ -314,48 +314,24 @@ def test_invalid_query
314314
assert_equal expected_errors, result["errors"].map { _1.slice("message", "path") }
315315
end
316316

317-
def test_errors_are_handled_by_default
318-
client = GraphQL::Stitching::Client.new(locations: {
319-
products: {
320-
schema: Schemas::Example::Products,
321-
}
322-
})
323-
324-
result = client.execute('query { invalidSelection }', validate: false)
325-
326-
expected_errors = [{
327-
"message" => "An unexpected error occured.",
328-
}]
329-
330-
assert_nil result["data"]
331-
assert_equal expected_errors, result["errors"]
332-
end
333-
334-
def test_errors_trigger_hooks_that_may_return_a_custom_message
317+
def test_stitching_errors_are_handled
335318
called = false
336319
client = GraphQL::Stitching::Client.new(locations: {
337320
products: {
338321
schema: Schemas::Example::Products,
339322
}
340323
})
324+
client.on_error { called = true }
341325

342-
client.on_error do |_req, _err|
343-
called = true
344-
end
345-
346-
result = client.execute(
347-
query: "query { invalidSelection }",
348-
context: { request_id: "R2d2c3P0" },
349-
validate: false
350-
)
326+
result = client.execute('query { invalidSelection }', validate: false)
351327

352328
expected_errors = [{
353329
"message" => "An unexpected error occured.",
354330
}]
355331

332+
assert called
356333
assert_nil result["data"]
357334
assert_equal expected_errors, result["errors"]
358-
assert called
359335
end
360336

361337
def test_passes_composer_options_through_to_composition
@@ -377,50 +353,4 @@ def test_errors_for_composer_options_given_with_precomposed_supergraph
377353
)
378354
end
379355
end
380-
381-
class MyClient < GraphQL::Stitching::Client
382-
def merge_descriptions(values_by_location, _info)
383-
values_by_location.values.join("/")
384-
end
385-
end
386-
387-
def test_from_definition_builds_with_invocation_class
388-
alpha = %|
389-
type T { id:ID! a:String }
390-
type Query { a(id:ID!):T @stitch(key: "id") }
391-
|
392-
bravo = %|
393-
type T { id:ID! b:String }
394-
type Query { b(id:ID!):T @stitch(key: "id") }
395-
|
396-
397-
sdl = compose_definitions({ "alpha" => alpha, "bravo" => bravo }).to_definition
398-
client = MyClient.from_definition(sdl, executables: {
399-
"alpha" => Proc.new {},
400-
"bravo" => Proc.new {},
401-
})
402-
assert client.is_a?(MyClient)
403-
end
404-
405-
def test_custom_client_acts_as_composition_formatter
406-
alpha = %|
407-
"""
408-
a
409-
"""
410-
type Query { a:Boolean }
411-
|
412-
bravo = %|
413-
"""
414-
b
415-
"""
416-
type Query { b:Boolean }
417-
|
418-
419-
client = MyClient.new(locations: {
420-
"alpha" => { schema: GraphQL::Schema.from_definition(alpha) },
421-
"bravo" => { schema: GraphQL::Schema.from_definition(bravo) },
422-
})
423-
424-
assert_equal "a/b", client.supergraph.schema.query.description
425-
end
426356
end

0 commit comments

Comments
 (0)