From f977a4a30a18a92a92a8f4fef59b73c00c459429 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 19 Jun 2022 15:04:48 +0300 Subject: [PATCH 1/2] Allow Edge API endpoints to receive body --- packages/next/server/body-streams.ts | 2 +- packages/next/server/next-server.ts | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/next/server/body-streams.ts b/packages/next/server/body-streams.ts index 19a3c20c004b9..9f0abca87f594 100644 --- a/packages/next/server/body-streams.ts +++ b/packages/next/server/body-streams.ts @@ -7,7 +7,7 @@ type BodyStream = ReadableStream /** * Creates a ReadableStream from a Node.js HTTP request */ -function requestToBodyStream(request: IncomingMessage): BodyStream { +export function requestToBodyStream(request: IncomingMessage): BodyStream { const transform = new Primitives.TransformStream({ start(controller) { request.on('data', (chunk) => controller.enqueue(chunk)) diff --git a/packages/next/server/next-server.ts b/packages/next/server/next-server.ts index 351d559aa434a..d6f57225c4f19 100644 --- a/packages/next/server/next-server.ts +++ b/packages/next/server/next-server.ts @@ -81,7 +81,11 @@ import { urlQueryToSearchParams } from '../shared/lib/router/utils/querystring' import ResponseCache from '../server/response-cache' import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash' import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info' -import { bodyStreamToNodeStream, clonableBodyForRequest } from './body-streams' +import { + bodyStreamToNodeStream, + clonableBodyForRequest, + requestToBodyStream, +} from './body-streams' import { checkIsManualRevalidate } from './api-utils' const shouldUseReactRoot = parseInt(React.version) >= 18 @@ -1495,8 +1499,9 @@ export default class NextNodeServer extends BaseServer { name: params.page, ...(params.params && { params: params.params }), }, - // TODO(gal): complete body - // body: originalBody?.cloneBodyStream(), + body: ['GET', 'HEAD'].includes(params.req.method) + ? undefined + : requestToBodyStream(params.req.originalRequest), }, useCache: !this.nextConfig.experimental.runtime, onWarning: (_warning: Error) => { From b5b5462475e3723ccd3187f7b5858e0f725f8801 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Sun, 19 Jun 2022 15:13:49 +0300 Subject: [PATCH 2/2] Add a test --- .../app/pages/api/edge.js | 11 ++++++ .../index.test.ts | 35 +++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 test/e2e/edge-api-endpoints-can-receive-body/app/pages/api/edge.js create mode 100644 test/e2e/edge-api-endpoints-can-receive-body/index.test.ts diff --git a/test/e2e/edge-api-endpoints-can-receive-body/app/pages/api/edge.js b/test/e2e/edge-api-endpoints-can-receive-body/app/pages/api/edge.js new file mode 100644 index 0000000000000..26bcb1402fe01 --- /dev/null +++ b/test/e2e/edge-api-endpoints-can-receive-body/app/pages/api/edge.js @@ -0,0 +1,11 @@ +export default async (req) => { + if (!req.body) { + return new Response('Body is required', { status: 400 }) + } + + return new Response(`got: ${await req.text()}`) +} + +export const config = { + runtime: 'experimental-edge', +} diff --git a/test/e2e/edge-api-endpoints-can-receive-body/index.test.ts b/test/e2e/edge-api-endpoints-can-receive-body/index.test.ts new file mode 100644 index 0000000000000..09d6aee901fb7 --- /dev/null +++ b/test/e2e/edge-api-endpoints-can-receive-body/index.test.ts @@ -0,0 +1,35 @@ +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import { fetchViaHTTP } from 'next-test-utils' +import path from 'path' + +describe('Edge API endpoints can receive body', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/api/edge.js': new FileRef( + path.resolve(__dirname, './app/pages/api/edge.js') + ), + }, + dependencies: {}, + }) + }) + afterAll(() => next.destroy()) + + it('reads the body as text', async () => { + const res = await fetchViaHTTP( + next.url, + '/api/edge', + {}, + { + body: 'hello, world.', + method: 'POST', + } + ) + + expect(res.status).toBe(200) + expect(await res.text()).toBe('got: hello, world.') + }) +})