Skip to content

Commit

Permalink
Allow Edge Functions to receive body (#37822)
Browse files Browse the repository at this point in the history
This PR enables Edge API endpoints to receive a body.
This wasn't in the original PR, as thankfully pointed out by @zaiste in [this comment](#37481 (comment)) 🙏

## Related

- Fixes #37821

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`
  • Loading branch information
Schniz committed Jun 20, 2022
1 parent c84c7c8 commit 4ed0b78
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/next/server/body-streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type BodyStream = ReadableStream<Uint8Array>
/**
* 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<Uint8Array, Uint8Array>({
start(controller) {
request.on('data', (chunk) => controller.enqueue(chunk))
Expand Down
11 changes: 8 additions & 3 deletions packages/next/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) => {
Expand Down
11 changes: 11 additions & 0 deletions test/e2e/edge-api-endpoints-can-receive-body/app/pages/api/edge.js
Original file line number Diff line number Diff line change
@@ -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',
}
35 changes: 35 additions & 0 deletions test/e2e/edge-api-endpoints-can-receive-body/index.test.ts
Original file line number Diff line number Diff line change
@@ -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.')
})
})

0 comments on commit 4ed0b78

Please sign in to comment.