Skip to content

Commit 066f84a

Browse files
authored
[minor] Add error-throwing hook last (#673)
By running user-provided hooks first, users can nullify `response.body.errors` and avoid the subsequent error.
1 parent e3c0e0b commit 066f84a

File tree

2 files changed

+89
-11
lines changed

2 files changed

+89
-11
lines changed

index.js

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -286,36 +286,39 @@ Shopify.prototype.graphql = function graphql(data, variables) {
286286
timeout: this.options.timeout
287287
};
288288

289-
const afterResponse = (res) => {
290-
if (res.body) {
291-
if (res.body.extensions && res.body.extensions.cost) {
292-
this.updateGraphqlLimits(res.body.extensions.cost);
293-
}
289+
const updateGqlLimits = (res) => {
290+
if (res.body && res.body.extensions && res.body.extensions.cost) {
291+
this.updateGraphqlLimits(res.body.extensions.cost);
292+
}
294293

295-
if (Array.isArray(res.body.errors)) {
296-
// Make Got consider this response errored and retry if needed.
297-
throw new Error(res.body.errors[0].message);
298-
}
294+
return res;
295+
};
296+
297+
const maybeError = (res) => {
298+
if (res.body && Array.isArray(res.body.errors)) {
299+
throw new Error(res.body.errors[0].message);
299300
}
300301

301302
return res;
302303
};
303304

304305
if (this.options.hooks) {
305306
options.hooks = { ...this.options.hooks };
306-
options.hooks.afterResponse = [afterResponse];
307+
options.hooks.afterResponse = [updateGqlLimits];
307308
options.hooks.beforeError = [decorateError];
308309

309310
if (this.options.hooks.afterResponse) {
310311
options.hooks.afterResponse.push(...this.options.hooks.afterResponse);
311312
}
312313

314+
options.hooks.afterResponse.push(maybeError);
315+
313316
if (this.options.hooks.beforeError) {
314317
options.hooks.beforeError.push(...this.options.hooks.beforeError);
315318
}
316319
} else {
317320
options.hooks = {
318-
afterResponse: [afterResponse],
321+
afterResponse: [updateGqlLimits, maybeError],
319322
beforeError: [decorateError]
320323
};
321324
}

test/shopify.test.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,81 @@ describe('Shopify', () => {
917917
);
918918
});
919919

920+
it('can add a hook to not throw an error when the response has errors', () => {
921+
const customerDataErrors = [
922+
{
923+
message:
924+
'This app is not approved to use the email field. See https://partners.shopify.com/1/apps/1/customer_data for more details.',
925+
path: ['customers', 'edges', '0', 'node', 'email'],
926+
extensions: {
927+
code: 'ACCESS_DENIED',
928+
documentation:
929+
'https://partners.shopify.com/1/apps/1/customer_data',
930+
requiredAccess:
931+
'Shopify approval is required before using the email field.'
932+
}
933+
},
934+
{
935+
message:
936+
'This app is not approved to use the firstName field. See https://partners.shopify.com/1/apps/1/customer_data for more details.',
937+
path: ['customers', 'edges', '0', 'node', 'firstName'],
938+
extensions: {
939+
code: 'ACCESS_DENIED',
940+
documentation:
941+
'https://partners.shopify.com/1/apps/1/customer_data',
942+
requiredAccess:
943+
'Shopify approval is required before using the firstName field.'
944+
}
945+
}
946+
];
947+
948+
let calledWithErrors = undefined;
949+
950+
const shopify = new Shopify({
951+
shopName,
952+
accessToken,
953+
hooks: {
954+
afterResponse: [
955+
(res) => {
956+
if (res.body && res.body.errors) {
957+
calledWithErrors = res.body.errors;
958+
959+
res.body.errors = undefined;
960+
}
961+
962+
return res;
963+
}
964+
]
965+
}
966+
});
967+
968+
scope.post('/admin/api/graphql.json').reply(200, {
969+
data: {
970+
customers: {
971+
edges: [
972+
{
973+
node: {
974+
id: 'gid://shopify/Customer/1234567890',
975+
email: null,
976+
firstName: null
977+
}
978+
}
979+
]
980+
}
981+
},
982+
errors: customerDataErrors
983+
});
984+
985+
return shopify.graphql('query').then((result) => {
986+
expect(calledWithErrors).to.deep.equal(customerDataErrors);
987+
expect(result.customers.edges[0].node.id).to.equal(
988+
'gid://shopify/Customer/1234567890'
989+
);
990+
expect(result.customers.edges[0].node.email).to.equal(null);
991+
expect(result.customers.edges[0].node.firstName).to.equal(null);
992+
});
993+
});
994+
920995
it('uses basic auth as intended', () => {
921996
const shopify = new Shopify({ shopName, apiKey, password });
922997

0 commit comments

Comments
 (0)