diff --git a/.changeset/quiet-owls-occur.md b/.changeset/quiet-owls-occur.md new file mode 100644 index 0000000000..f3b0e34055 --- /dev/null +++ b/.changeset/quiet-owls-occur.md @@ -0,0 +1,5 @@ +--- +'graphql-yoga': minor +--- + +Support variable batching diff --git a/packages/graphql-yoga/__tests__/batching.spec.ts b/packages/graphql-yoga/__tests__/batching.spec.ts index 5681835aa5..3f9797c277 100644 --- a/packages/graphql-yoga/__tests__/batching.spec.ts +++ b/packages/graphql-yoga/__tests__/batching.spec.ts @@ -7,12 +7,14 @@ describe('Batching', () => { type Query { hello: String bye: String + greetings(name: String!): String! } `, resolvers: { Query: { hello: () => 'hello', bye: () => 'bye', + greetings: (_root, { name }) => `hello, ${name}`, }, }, }); @@ -352,4 +354,32 @@ describe('Batching', () => { expect(contexts[0]!.i).toEqual(1); expect(contexts[1]!.i).toEqual(2); }); + it('variable batching', async () => { + const yoga = createYoga({ + schema, + batching: {}, + }); + const query = /* GraphQL */ ` + query ($name: String!) { + greetings(name: $name) + } + `; + const res = await yoga.fetch('http://yoga/graphql', { + method: 'POST', + headers: { + accept: 'application/graphql-response+json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables: [{ name: 'Alice' }, { name: 'Bob' }, { name: 'Charlie' }], + }), + }); + const result = await res.json(); + expect(result).toEqual([ + { data: { greetings: 'hello, Alice' } }, + { data: { greetings: 'hello, Bob' } }, + { data: { greetings: 'hello, Charlie' } }, + ]); + }); }); diff --git a/packages/graphql-yoga/src/server.ts b/packages/graphql-yoga/src/server.ts index 44302af713..a47899c3be 100644 --- a/packages/graphql-yoga/src/server.ts +++ b/packages/graphql-yoga/src/server.ts @@ -83,6 +83,7 @@ import { YogaMaskedErrorOpts, } from './types.js'; import { maskError } from './utils/mask-error.js'; +import { processBatchedParams } from './utils/process-batched-params.js'; /** * Configuration options for the server @@ -666,6 +667,7 @@ export class YogaServer< if (response) { return response; } + requestParserResult = processBatchedParams(requestParserResult!); const getResultForParams = this.instrumentation?.operation ? (payload: { request: Request; params: GraphQLParams }, context: any) => { const instrumented = getInstrumented({ context, request: payload.request }); diff --git a/packages/graphql-yoga/src/utils/process-batched-params.ts b/packages/graphql-yoga/src/utils/process-batched-params.ts new file mode 100644 index 0000000000..c7fb9e6311 --- /dev/null +++ b/packages/graphql-yoga/src/utils/process-batched-params.ts @@ -0,0 +1,16 @@ +import { GraphQLParams } from '../types.js'; + +export function processBatchedParams( + params: GraphQLParams | GraphQLParams[], +): GraphQLParams | GraphQLParams[] { + if (Array.isArray(params)) { + return params.flatMap(param => processBatchedParams(param)); + } + if (Array.isArray(params.variables)) { + return params.variables.map(variables => ({ + ...params, + variables, + })); + } + return params; +}