From 4199e62e21c7b37c47542168709e7176502d3251 Mon Sep 17 00:00:00 2001 From: Richard Wu <10563314+richardwu@users.noreply.github.com> Date: Wed, 2 Apr 2025 22:38:25 -0400 Subject: [PATCH 1/4] Add `allowOperation` to `batchMiddleware`. --- src/index.d.ts | 1 + src/middlewares/__tests__/batch-test.js | 54 +++++++++++++++++++++++++ src/middlewares/batch.js | 6 +++ 3 files changed, 61 insertions(+) diff --git a/src/index.d.ts b/src/index.d.ts index 51d62fc..6b13013 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -148,6 +148,7 @@ export type BatchMiddlewareOpts = { maxBatchSize?: number; maxRequestsPerBatch?: number; allowMutations?: boolean; + allowOperation?: (operation: ConcreteBatch) => boolean; method?: 'POST' | 'GET'; headers?: Headers | Promise | ((req: RelayRequestBatch) => Headers | Promise); // Available request modes in fetch options. For details see https://fetch.spec.whatwg.org/#requests diff --git a/src/middlewares/__tests__/batch-test.js b/src/middlewares/__tests__/batch-test.js index a4a8800..9b493d6 100644 --- a/src/middlewares/__tests__/batch-test.js +++ b/src/middlewares/__tests__/batch-test.js @@ -438,6 +438,60 @@ describe('middlewares/batch', () => { }); }); + describe('option `allowOperation`', () => { + beforeEach(() => { + fetchMock.restore(); + }); + + it('should not batch requests that return false', async () => { + fetchMock.mock({ + matcher: '/graphql', + response: { + status: 200, + body: { data: {} }, + }, + method: 'POST', + }); + fetchMock.mock({ + matcher: '/graphql/batch', + response: { + status: 200, + body: [{ data: {} }, { data: {} }], + }, + method: 'POST', + }); + + const req1 = mockReq(1, { + query: 'abc', + }); + const req2 = mockReq(2); + const req3 = mockReq(3); + const req4 = mockReq(4, { + query: 'def', + }); + const req5 = mockReq(4, { + query: 'no', + }); + + const rnl = new RelayNetworkLayer([ + batchMiddleware({ + allowOperation: (op) => !['abc', 'def'].includes(op.name), + }), + ]); + await Promise.all([ + req1.execute(rnl), + req2.execute(rnl), + req3.execute(rnl), + req4.execute(rnl), + req5.execute(rnl), + ]); + const batchReqs = fetchMock.calls('/graphql/batch'); + const singleReqs = fetchMock.calls('/graphql'); + expect(batchReqs).toHaveLength(1); + expect(singleReqs).toHaveLength(2); + }); + }); + it('should pass fetch options', async () => { fetchMock.mock({ matcher: '/graphql/batch', diff --git a/src/middlewares/batch.js b/src/middlewares/batch.js index 19a66d3..dbd611f 100644 --- a/src/middlewares/batch.js +++ b/src/middlewares/batch.js @@ -59,6 +59,7 @@ export default function batchMiddleware(options?: BatchMiddlewareOpts): Middlewa const batchUrl = opts.batchUrl || '/graphql/batch'; const maxBatchSize = opts.maxBatchSize || DEFAULT_BATCH_SIZE; const maxRequestsPerBatch = opts.maxRequestsPerBatch || 0; // 0 is the same as no limit + const allowOperation = opts.allowOperation || true; const singleton = {}; const fetchOpts = {}; @@ -81,6 +82,10 @@ export default function batchMiddleware(options?: BatchMiddlewareOpts): Middlewa ); } + if (isFunction(opts.allowOperation) && !opts.allowOperation(req.operation)) { + return next(req); + } + // req with FormData can not be batched if (req.isFormData()) { return next(req); @@ -97,6 +102,7 @@ export default function batchMiddleware(options?: BatchMiddlewareOpts): Middlewa singleton, maxBatchSize, maxRequestsPerBatch, + allowOperation, fetchOpts, }); }; From 9a75961cf9c49723c0b3131967b75666aba71ec3 Mon Sep 17 00:00:00 2001 From: Richard Wu <10563314+richardwu@users.noreply.github.com> Date: Wed, 2 Apr 2025 22:40:26 -0400 Subject: [PATCH 2/4] Fix test. --- src/middlewares/__tests__/batch-test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/middlewares/__tests__/batch-test.js b/src/middlewares/__tests__/batch-test.js index 9b493d6..3f9ce1c 100644 --- a/src/middlewares/__tests__/batch-test.js +++ b/src/middlewares/__tests__/batch-test.js @@ -456,7 +456,7 @@ describe('middlewares/batch', () => { matcher: '/graphql/batch', response: { status: 200, - body: [{ data: {} }, { data: {} }], + body: [{ data: {} }, { data: {} }, { data: {} }], }, method: 'POST', }); @@ -475,7 +475,7 @@ describe('middlewares/batch', () => { const rnl = new RelayNetworkLayer([ batchMiddleware({ - allowOperation: (op) => !['abc', 'def'].includes(op.name), + allowOperation: (op) => !['abc', 'def'].includes(op.query), }), ]); await Promise.all([ From 14e0dcd3bc96571aa1e0c56994cd61a291148753 Mon Sep 17 00:00:00 2001 From: Richard Wu <10563314+richardwu@users.noreply.github.com> Date: Wed, 2 Apr 2025 22:43:15 -0400 Subject: [PATCH 3/4] Test console. --- src/middlewares/__tests__/batch-test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/middlewares/__tests__/batch-test.js b/src/middlewares/__tests__/batch-test.js index 3f9ce1c..96c90a2 100644 --- a/src/middlewares/__tests__/batch-test.js +++ b/src/middlewares/__tests__/batch-test.js @@ -475,7 +475,10 @@ describe('middlewares/batch', () => { const rnl = new RelayNetworkLayer([ batchMiddleware({ - allowOperation: (op) => !['abc', 'def'].includes(op.query), + allowOperation: (op) => { + console.log('op', op); + return !['abc', 'def'].includes(op.query); + }, }), ]); await Promise.all([ From 70d6ba90d7ee5db41a32154363fd3e33f03793c4 Mon Sep 17 00:00:00 2001 From: Richard Wu <10563314+richardwu@users.noreply.github.com> Date: Wed, 2 Apr 2025 22:46:23 -0400 Subject: [PATCH 4/4] Fix test once again + missing attribute. --- src/middlewares/__tests__/batch-test.js | 5 +---- src/middlewares/batch.js | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/middlewares/__tests__/batch-test.js b/src/middlewares/__tests__/batch-test.js index 96c90a2..92440ed 100644 --- a/src/middlewares/__tests__/batch-test.js +++ b/src/middlewares/__tests__/batch-test.js @@ -475,10 +475,7 @@ describe('middlewares/batch', () => { const rnl = new RelayNetworkLayer([ batchMiddleware({ - allowOperation: (op) => { - console.log('op', op); - return !['abc', 'def'].includes(op.query); - }, + allowOperation: (op) => !['abc', 'def'].includes(op.text), }), ]); await Promise.all([ diff --git a/src/middlewares/batch.js b/src/middlewares/batch.js index dbd611f..6307b14 100644 --- a/src/middlewares/batch.js +++ b/src/middlewares/batch.js @@ -5,7 +5,7 @@ import { isFunction } from '../utils'; import RelayRequestBatch from '../RelayRequestBatch'; import RelayRequest from '../RelayRequest'; import type RelayResponse from '../RelayResponse'; -import type { Middleware, FetchOpts } from '../definition'; +import type { Middleware, FetchOpts, ConcreteBatch } from '../definition'; import RRNLError from '../RRNLError'; // Max out at roughly 100kb (express-graphql imposed max) @@ -22,6 +22,7 @@ export type BatchMiddlewareOpts = {| maxBatchSize?: number, maxRequestsPerBatch?: number, allowMutations?: boolean, + allowOperation?: (operation: ConcreteBatch) => boolean, method?: 'POST' | 'GET', headers?: Headers | Promise | ((req: RelayRequestBatch) => Headers | Promise), // Avaliable request modes in fetch options. For details see https://fetch.spec.whatwg.org/#requests