Skip to content

Commit 84cd775

Browse files
Correctly handle multiple user errors (#64)
* Correctly handle multiple user errors * refactor: bring `error_code` back * test: add multiple user errors test
1 parent ddd5f27 commit 84cd775

File tree

4 files changed

+99
-12
lines changed

4 files changed

+99
-12
lines changed

lib/shopify_graphql/client.rb

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,34 +114,61 @@ def handle_graphql_errors(response)
114114
ConnectionError.new(response: response)
115115
end
116116
exception.error_code = error_code
117+
exception.error_codes = [ error_code ]
118+
exception.messages = [ error.message ]
117119
raise exception, error_message
118120
end
119121

120122
def handle_user_errors(response)
121123
return response if response.userErrors.blank?
122124

123125
error = response.userErrors.first
124-
error_code = error.code
125-
error_message = generate_error_message(
126-
message: error.message,
127-
code: error_code,
128-
fields: error.field,
126+
errors = response.userErrors
127+
error_message = generate_user_errors_message(
128+
messages: errors.map(&:message),
129+
codes: errors.map(&:code),
130+
fields: errors.map(&:field),
129131
)
130132

131133
exception = UserError.new(response: response)
132-
exception.error_code = error_code
133-
exception.fields = error.field
134+
exception.error_code = error.code
135+
exception.error_codes = errors.map(&:code)
136+
exception.fields = errors.map(&:field)
137+
exception.messages = errors.map(&:message)
134138
raise exception, error_message
135139
end
136140

137-
def generate_error_message(message: nil, code: nil, doc: nil, fields: nil)
141+
def generate_error_message(message: nil, code: nil, doc: nil)
138142
string = "Failed.".dup
139143
string << " Response code = #{code}." if code
140144
string << " Response message = #{message}.".gsub("..", ".") if message
141145
string << " Documentation = #{doc}." if doc
142-
string << " Fields = #{fields}." if fields
143146
string
144147
end
148+
149+
def generate_user_errors_message(messages: nil, codes: nil, fields: [])
150+
if fields.any?
151+
field_count = fields.size
152+
result = ["#{field_count} #{"field".pluralize(field_count)} have failed:"]
153+
154+
fields.each.with_index do |field, index|
155+
field_details = ["\n-"]
156+
field_details << "Response code = #{codes[index]}." if codes&.at(index)
157+
field_details << "Response message = #{messages[index]}.".gsub("..", ".") if messages&.at(index)
158+
field_details << "Field = #{field}." if field
159+
160+
result << field_details.join(" ")
161+
end
162+
163+
result.join("\n")
164+
else
165+
result = ["Failed."]
166+
result << "Response code = #{codes.join(", ")}." if codes&.any?
167+
result << "Response message = #{messages&.join(", ")}.".gsub("..", ".") if messages&.any?
168+
169+
result.join(" ")
170+
end
171+
end
145172
end
146173

147174
class << self

lib/shopify_graphql/exceptions.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module ShopifyGraphql
22
class ConnectionError < ShopifyAPI::Errors::HttpResponseError
3-
attr_accessor :error_code, :fields
3+
attr_accessor :error_code, :error_codes, :fields, :messages
44

55
def initialize(response: nil)
66
unless response

test/error_handling_test.rb

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,32 @@ class ErrorHandlingTest < ActiveSupport::TestCase
4444
rescue ShopifyGraphql::UserError => error
4545
assert_equal 200, error.code
4646
assert_equal "TAKEN", error.error_code
47+
assert error.error_codes.include?("TAKEN")
4748
assert_includes error.message, "Key is in use for Product metafields"
48-
assert_equal ["definition", "key"], error.fields
49+
assert_includes error.messages, "Key is in use for Product metafields on the 'xxx' namespace."
50+
assert error.fields.include?(["definition", "key"])
4951
end
5052
end
5153

54+
test "multiple user errors" do
55+
fake("mutations/multiple_user_errors.json", SIMPLE_QUERY)
56+
57+
begin
58+
response = ShopifyGraphql.execute(SIMPLE_QUERY)
59+
ShopifyGraphql::Client.new.handle_user_errors(response.data.metafieldsSet)
60+
rescue ShopifyGraphql::UserError => error
61+
assert_equal 200, error.code
62+
assert_equal "INVALID_VALUE", error.error_code
63+
assert error.error_codes.include?("INVALID_VALUE")
64+
assert_equal error.error_codes, ["INVALID_VALUE", "INVALID_VALUE"]
65+
assert_includes error.messages, "Value does not exist in provided choices: [\"Male\", \"Female\", \"Other\"]."
66+
assert_includes error.message, "2 fields have failed"
67+
assert_includes error.message, "Value has a maximum length of 10."
68+
assert_equal error.fields, [["metafields", "0", "value"], ["metafields", "1", "value"]]
69+
end
70+
end
71+
72+
5273
test "server error" do
5374
fake("mutations/server_error.json", SIMPLE_QUERY)
5475

@@ -57,7 +78,8 @@ class ErrorHandlingTest < ActiveSupport::TestCase
5778
rescue ShopifyGraphql::ServerError => error
5879
assert_equal 200, error.code
5980
assert_equal "INTERNAL_SERVER_ERROR", error.error_code
60-
assert_includes error.message, "Looks like something went wrong on our end"
81+
assert_equal ["INTERNAL_SERVER_ERROR"], error.error_codes
82+
assert_includes error.messages, "Internal error. Looks like something went wrong on our end.\nRequest ID: XXXXX (include this in support requests)."
6183
end
6284
end
6385

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"data": {
3+
"metafieldsSet": {
4+
"metafields": [],
5+
"userErrors": [
6+
{
7+
"field": [
8+
"metafields",
9+
"0",
10+
"value"
11+
],
12+
"message": "Value does not exist in provided choices: [\"Male\", \"Female\", \"Other\"].",
13+
"code": "INVALID_VALUE"
14+
},
15+
{
16+
"field": [
17+
"metafields",
18+
"1",
19+
"value"
20+
],
21+
"message": "Value has a maximum length of 10.",
22+
"code": "INVALID_VALUE"
23+
}
24+
]
25+
}
26+
},
27+
"extensions": {
28+
"cost": {
29+
"requestedQueryCost": 10,
30+
"actualQueryCost": 10,
31+
"throttleStatus": {
32+
"maximumAvailable": 2000,
33+
"currentlyAvailable": 1990,
34+
"restoreRate": 100
35+
}
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)