From a361cc75ac27e212f997179ab8dc3fcdf807e2b9 Mon Sep 17 00:00:00 2001 From: Jesus Date: Thu, 7 Sep 2023 13:04:31 +0200 Subject: [PATCH 1/2] Allow missing path in error --- src/graphql-utlities.ts | 25 +++++++++++++++++-------- src/request.ts | 12 ++++++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/graphql-utlities.ts b/src/graphql-utlities.ts index 54a8e03..b8a1d25 100644 --- a/src/graphql-utlities.ts +++ b/src/graphql-utlities.ts @@ -9,19 +9,29 @@ import { export const PlainGraphQLError = z.object({ message: z.string(), locations: z.array(z.object({ line: z.number(), column: z.number() })), - path: z.array(z.union([z.string(), z.number()])), + path: z.array(z.union([z.string(), z.number()])).optional(), extensions: z.object({ code: z.string() }), }); export type PlainGraphQLError = z.infer; -export const PlainGraphQLResponse = z.object({ +const PlainSuccessfulGraphQLResponse = z.object({ data: z.unknown(), - errors: z.array(PlainGraphQLError).optional(), }); -export type PlainGraphQLResponse = z.infer; -export function isPlainGraphQLResponse(x: unknown): x is PlainGraphQLResponse { - return PlainGraphQLResponse.safeParse(x).success; +export function isPlainSuccessfulGraphQLResponse( + x: unknown +): x is z.infer { + return PlainSuccessfulGraphQLResponse.safeParse(x).success; +} + +const PlainFailedGraphQLResponse = z.object({ + errors: z.array(PlainGraphQLError), +}); + +export function isPlainFailedGraphQLResponse( + x: unknown +): x is z.infer { + return PlainFailedGraphQLResponse.safeParse(x).success; } const PlainMutationResponse = z.record( @@ -42,9 +52,8 @@ const PlainMutationResponse = z.record( }), }) ); -type PlainMutationResponse = z.infer; -function isPlainMutationResponse(x: unknown): x is PlainMutationResponse { +function isPlainMutationResponse(x: unknown): x is z.infer { return PlainMutationResponse.safeParse(x).success; } diff --git a/src/request.ts b/src/request.ts index 5fdf6de..e6ac8b9 100644 --- a/src/request.ts +++ b/src/request.ts @@ -4,7 +4,11 @@ import { print } from 'graphql'; import type { Context } from './context'; import type { PlainSDKError } from './error'; -import { getMutationErrorFromResponse, isPlainGraphQLResponse } from './graphql-utlities'; +import { + getMutationErrorFromResponse, + isPlainFailedGraphQLResponse, + isPlainSuccessfulGraphQLResponse, +} from './graphql-utlities'; import type { Result } from './result'; const defaultUrl = 'https://core-api.uk.plain.com/graphql/v1'; @@ -45,7 +49,7 @@ export async function request( } ); - if (!isPlainGraphQLResponse(res)) { + if (!isPlainSuccessfulGraphQLResponse(res)) { throw new Error('Unexpected response received'); } @@ -88,11 +92,11 @@ export async function request( }; } - if (err.response.status === 400 && isPlainGraphQLResponse(err.response.data)) { + if (err.response.status === 400 && isPlainFailedGraphQLResponse(err.response.data)) { return { error: { type: 'bad_request', - message: 'Missing or invalid arguments provided.', + message: 'Malformed query, missing or invalid arguments provided.', graphqlErrors: err.response.data.errors || [], requestId: getRequestId(err.response.headers), }, From 346bbce931c637be9eb87b52f9593e0bfe8f76e0 Mon Sep 17 00:00:00 2001 From: Jesus Date: Thu, 7 Sep 2023 13:13:34 +0200 Subject: [PATCH 2/2] Updated tests --- src/tests/query.test.ts | 2 +- src/tests/raw-request.test.ts | 41 +++++++++++++++++++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/tests/query.test.ts b/src/tests/query.test.ts index 5fc97f2..87df30e 100644 --- a/src/tests/query.test.ts +++ b/src/tests/query.test.ts @@ -110,7 +110,7 @@ describe('query test - customer by id', () => { const err: PlainSDKError = { type: 'bad_request', - message: 'Missing or invalid arguments provided.', + message: 'Malformed query, missing or invalid arguments provided.', graphqlErrors, requestId: 'req_1', }; diff --git a/src/tests/raw-request.test.ts b/src/tests/raw-request.test.ts index ac4b829..34910d2 100644 --- a/src/tests/raw-request.test.ts +++ b/src/tests/raw-request.test.ts @@ -3,7 +3,6 @@ import { describe, expect, test } from 'vitest'; import { PlainClient } from '..'; import type { PlainSDKError } from '../error'; -import { PlainGraphQLError } from '../graphql-utlities'; describe('raw request', () => { test('make a request as defined', async () => { @@ -60,16 +59,34 @@ describe('raw request', () => { scope.done(); }); - test('handles graphql errors', async () => { - const graphqlErrors: PlainGraphQLError[] = [ + test.each([ + [ { - message: 'Variable "$customerId" of required type "ID!" was not provided.', - locations: [{ line: 1, column: 20 }], - extensions: { code: 'BAD_USER_INPUT' }, - path: ['a', 1], + name: 'with path', + errors: [ + { + message: 'Variable "$customerId" of required type "ID!" was not provided.', + locations: [{ line: 1, column: 20 }], + extensions: { code: 'BAD_USER_INPUT' }, + path: ['a', 1], + }, + ], }, - ]; - + ], + [ + { + name: 'without path', + errors: [ + { + message: 'Variable "$customerId" of required type "ID!" was not provided.', + locations: [{ line: 1, column: 20 }], + extensions: { code: 'BAD_USER_INPUT' }, + }, + ], + }, + ], + ])('handles graphql errors ($testCase.name)', async (testCase) => { + const { errors } = testCase; const query = 'query customer { customer() { id }}'; const variables = {}; @@ -82,7 +99,7 @@ describe('raw request', () => { .reply( 400, { - errors: graphqlErrors, + errors, }, { 'apigw-requestid': 'req_2', @@ -97,8 +114,8 @@ describe('raw request', () => { const err: PlainSDKError = { type: 'bad_request', - message: 'Missing or invalid arguments provided.', - graphqlErrors, + message: 'Malformed query, missing or invalid arguments provided.', + graphqlErrors: errors, requestId: 'req_2', };