From 39714eb55150ca498039090000960f8ef10d2284 Mon Sep 17 00:00:00 2001 From: Valentin Cocaud Date: Thu, 27 Apr 2023 17:37:35 +0200 Subject: [PATCH] customize not found error message --- .../__tests__/persisted-operations.spec.ts | 47 ++++++++++++++++++- .../plugins/persisted-operations/src/index.ts | 19 +++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts b/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts index 596b522717..652621b8e3 100644 --- a/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts +++ b/packages/plugins/persisted-operations/__tests__/persisted-operations.spec.ts @@ -1,4 +1,7 @@ -import { usePersistedOperations } from '@graphql-yoga/plugin-persisted-operations' +import { + CustomPersistedQueryErrors, + usePersistedOperations, +} from '@graphql-yoga/plugin-persisted-operations' import { DocumentNode, parse, validate } from 'graphql' import { createSchema, createYoga, GraphQLParams } from 'graphql-yoga' @@ -115,6 +118,7 @@ describe('Persisted Operations', () => { expect(body.errors).toBeDefined() expect(body.errors[0].message).toBe('PersistedQueryOnly') }) + it('allows non-persisted operations via allowArbitraryOperations flag', async () => { const store = new Map() @@ -150,6 +154,7 @@ describe('Persisted Operations', () => { expect(body.errors).toBeUndefined() expect(body.data).toEqual({ __typename: 'Query' }) }) + it('allows non-persisted operations via allowArbitraryOperations based on a header', async () => { const store = new Map() @@ -187,6 +192,7 @@ describe('Persisted Operations', () => { expect(body.errors).toBeUndefined() expect(body.data).toEqual({ __typename: 'Query' }) }) + it('should respect the custom getPersistedQueryKey implementation (Relay)', async () => { const store = new Map() const yoga = createYoga({ @@ -356,4 +362,43 @@ describe('Persisted Operations', () => { expect(validateFn).not.toHaveBeenCalled() }) + + it('should allow to customize not found error message with a string', async () => { + const error = await generateNotFoundError({ notFound: 'Not found' }) + expect(error.message).toBe('Not found') + }) }) + +async function generateNotFoundError(customErrors: CustomPersistedQueryErrors) { + const yoga = createYoga({ + plugins: [ + usePersistedOperations({ + getPersistedOperation() { + return null + }, + customErrors, + }), + ], + schema, + }) + + const response = await yoga.fetch('http://yoga/graphql', { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ + extensions: { + persistedQuery: { + version: 1, + sha256Hash: + 'ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38', + }, + }, + }), + }) + + const body = await response.json() + expect(body.errors).toBeDefined() + return body.errors[0] +} diff --git a/packages/plugins/persisted-operations/src/index.ts b/packages/plugins/persisted-operations/src/index.ts index 7601179ab7..60ce22c119 100644 --- a/packages/plugins/persisted-operations/src/index.ts +++ b/packages/plugins/persisted-operations/src/index.ts @@ -50,6 +50,20 @@ export type UsePersistedOperationsOptions = { * Whether to skip validation of the persisted operation */ skipDocumentValidation?: boolean + + /** + * Custom errors to be thrown + */ + customErrors?: CustomPersistedQueryErrors +} + +export type CustomErrorFactory = string + +export type CustomPersistedQueryErrors = { + /** + * Error to be thrown when the persisted operation is not found + */ + notFound?: CustomErrorFactory } export function usePersistedOperations< @@ -60,6 +74,7 @@ export function usePersistedOperations< extractPersistedOperationId = defaultExtractPersistedOperationId, getPersistedOperation, skipDocumentValidation = false, + customErrors, }: UsePersistedOperationsOptions): Plugin { const operationASTByRequest = new WeakMap() const persistedOperationRequest = new WeakSet() @@ -84,7 +99,9 @@ export function usePersistedOperations< const persistedQuery = await getPersistedOperation(persistedOperationKey) if (persistedQuery == null) { - throw createGraphQLError('PersistedQueryNotFound') + throw createGraphQLError( + customErrors?.notFound ?? 'PersistedQueryNotFound', + ) } if (typeof persistedQuery === 'object') {