diff --git a/packages/apollo-server-core/src/runHttpQuery.ts b/packages/apollo-server-core/src/runHttpQuery.ts index 5440463b202..a7cf41757f2 100644 --- a/packages/apollo-server-core/src/runHttpQuery.ts +++ b/packages/apollo-server-core/src/runHttpQuery.ts @@ -187,6 +187,11 @@ export async function runHttpQuery( !optionsObject.persistedQueries || !optionsObject.persistedQueries.cache ) { + if (isBatch) { + // A batch can contain another query that returns data, + // so we don't error out the entire request with an HttpError + throw new PersistedQueryNotSupportedError(); + } // Return 200 to simplify processing: we want this to be intepreted by // the client as data worth interpreting, not an error. throwHttpGraphQLError( @@ -203,6 +208,11 @@ export async function runHttpQuery( if (queryString === undefined) { queryString = await optionsObject.persistedQueries.cache.get(sha); if (!queryString) { + if (isBatch) { + // A batch can contain multiple undefined persisted queries, + // so we don't error out the entire request with an HttpError + throw new PersistedQueryNotFoundError(); + } throwHttpGraphQLError( 200, [new PersistedQueryNotFoundError()], diff --git a/packages/apollo-server-integration-testsuite/src/index.ts b/packages/apollo-server-integration-testsuite/src/index.ts index d50c1dc41d6..c9e54348fd3 100644 --- a/packages/apollo-server-integration-testsuite/src/index.ts +++ b/packages/apollo-server-integration-testsuite/src/index.ts @@ -942,6 +942,7 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => { describe('Persisted Queries', () => { const query = '{testString}'; + const query2 = '{ testString }'; const hash = sha256 .create() @@ -954,6 +955,16 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => { }, }; + const extensions2 = { + persistedQuery: { + version: VERSION, + sha256Hash: sha256 + .create() + .update(query2) + .hex(), + }, + }; + beforeEach(async () => { const map = new Map(); const cache = { @@ -1005,6 +1016,51 @@ export default (createApp: CreateAppFunc, destroyApp?: DestroyAppFunc) => { expect(result.body.errors).not.to.exist; }); + it('returns with batched persisted queries', async () => { + const errors = await request(app) + .post('/graphql') + .send([ + { + extensions, + }, + { + extensions: extensions2, + }, + ]); + + expect(errors.body[0].data).to.not.exist; + expect(errors.body[1].data).to.not.exist; + expect(errors.body[0].errors[0].message).to.equal( + 'PersistedQueryNotFound', + ); + expect(errors.body[0].errors[0].extensions.code).to.equal( + 'PERSISTED_QUERY_NOT_FOUND', + ); + expect(errors.body[1].errors[0].message).to.equal( + 'PersistedQueryNotFound', + ); + expect(errors.body[1].errors[0].extensions.code).to.equal( + 'PERSISTED_QUERY_NOT_FOUND', + ); + + const result = await request(app) + .post('/graphql') + .send([ + { + extensions, + query, + }, + { + extensions: extensions2, + query: query2, + }, + ]); + + expect(result.body[0].data).to.deep.equal({ testString: 'it works' }); + expect(result.body[0].data).to.deep.equal({ testString: 'it works' }); + expect(result.body.errors).not.to.exist; + }); + it('returns result on the persisted query', async () => { await request(app) .post('/graphql')