From 2288ed3e676e59ff91e58d35096b958ee7523e46 Mon Sep 17 00:00:00 2001 From: jer-k Date: Fri, 19 Jul 2024 12:17:56 -0700 Subject: [PATCH 1/2] Changes to the incremental responses to ensure they stream the responses back instead of batching them all together --- src/__tests__/integration.test.ts | 1 - src/startServerAndCreateNextHandler.ts | 37 +++++++++++++++----------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/__tests__/integration.test.ts b/src/__tests__/integration.test.ts index cb232de..5bfafec 100644 --- a/src/__tests__/integration.test.ts +++ b/src/__tests__/integration.test.ts @@ -56,7 +56,6 @@ describe('nextHandler', () => { }; }, { - noIncrementalDelivery: true, serverIsStartedInBackground: true, }, ); diff --git a/src/startServerAndCreateNextHandler.ts b/src/startServerAndCreateNextHandler.ts index 7b7d951..dff239f 100644 --- a/src/startServerAndCreateNextHandler.ts +++ b/src/startServerAndCreateNextHandler.ts @@ -4,6 +4,7 @@ import { isNextApiRequest } from './lib/isNextApiRequest'; import { ApolloServer, BaseContext, ContextFunction } from '@apollo/server'; import { NextApiRequest, NextApiResponse } from 'next'; import { NextRequest } from 'next/server'; +import { Readable } from 'stream'; import { parse } from 'url'; type HandlerRequest = NextApiRequest | NextRequest | Request; @@ -49,34 +50,38 @@ function startServerAndCreateNextHandler< if (httpGraphQLResponse.body.kind === 'complete') { res.send(httpGraphQLResponse.body.string); + res.end(); } else { - for await (const chunk of httpGraphQLResponse.body.asyncIterator) { - res.write(chunk); - } + res.send(Readable.from(httpGraphQLResponse.body.asyncIterator)); } - res.end(); return; } - const body = []; - - if (httpGraphQLResponse.body.kind === 'complete') { - body.push(httpGraphQLResponse.body.string); - } else { - for await (const chunk of httpGraphQLResponse.body.asyncIterator) { - body.push(chunk); - } - } - const headers: Record = {}; - for (const [key, value] of httpGraphQLResponse.headers) { headers[key] = value; } // eslint-disable-next-line consistent-return - return new Response(body.join(''), { headers, status: httpGraphQLResponse.status || 200 }); + return new Response( + httpGraphQLResponse.body.kind === 'complete' + ? httpGraphQLResponse.body.string + : new ReadableStream({ + async pull(controller) { + if (httpGraphQLResponse.body.kind === 'chunked') { + const { value, done } = await httpGraphQLResponse.body.asyncIterator.next(); + + if (done) { + controller.close(); + } else { + controller.enqueue(value); + } + } + }, + }), + { headers, status: httpGraphQLResponse.status || 200 }, + ); } return handler; From 90e57f8884110200e91a173c1d4cf20415018f3d Mon Sep 17 00:00:00 2001 From: Martin Nabhan <7613182+martinnabhan@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:10:27 +0900 Subject: [PATCH 2/2] Add changeset --- .changeset/witty-pens-nail.md | 5 +++++ README.md | 16 ++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 .changeset/witty-pens-nail.md diff --git a/.changeset/witty-pens-nail.md b/.changeset/witty-pens-nail.md new file mode 100644 index 0000000..5ec6d33 --- /dev/null +++ b/.changeset/witty-pens-nail.md @@ -0,0 +1,5 @@ +--- +'@as-integrations/next': minor +--- + +Add support for incremental delivery diff --git a/README.md b/README.md index cda87f2..7408275 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ An Apollo Server integration for use with Next.js. First create a Next.js API route by creating a file at for example `pages/api/graphql.js`. This API route will be accessible at `/api/graphql`. -Next create an Apollo Server instance and pass it to `startServerAndCreateNextHandler`: +Next, create an Apollo Server instance and pass it to `startServerAndCreateNextHandler`: ```js import { ApolloServer } from '@apollo/server'; @@ -46,15 +46,11 @@ The Next.js `req` and `res` objects are passed along to the context function. ## App Router (Route Handlers) -This integration has experimental support for [Next.js' App Router](https://nextjs.org/docs/app/building-your-application/routing/router-handlers), which is now the stable and default project structure for Next.js. +First create a Next.js Route Handler by creating a file at for example `app/api/graphql/route.js`. +This Route Handler will be accessible at `/api/graphql`. -Make sure you're on recent version of Next.js (13.4+), then create a new Route -Handler file, for example at `app/api/graphql/route.js`. - -This file's route handlers will be accessible at URI path `/api/graphql`. - -Next create an Apollo Server instance, pass it to `startServerAndCreateNextHandler` and -finally pass the handler to both a GET and a POST route handler: +Next, create an Apollo Server instance, pass it to `startServerAndCreateNextHandler` and +finally export the handler both as GET and POST: ```js import { startServerAndCreateNextHandler } from '@as-integrations/next'; @@ -83,7 +79,7 @@ const handler = startServerAndCreateNextHandler(server); export { handler as GET, handler as POST }; ``` -## Typescript +## TypeScript When using this integration with Route Handlers you will have to specify the type of the incoming request object (`Response` or `NextResponse`) for the context function to receive the correct type signature: