Skip to content

Commit

Permalink
Update app route handler proxy handling (#47088)
Browse files Browse the repository at this point in the history
This ensures our Proxy wrapping request fields works properly in the
edge-runtime by explicitly binding to the correct request instance.

x-ref: [slack
thread](https://vercel.slack.com/archives/C03UR7US95F/p1678730563467089?thread_ts=1678662292.695769&cid=C03UR7US95F)
  • Loading branch information
ijjk authored Mar 13, 2023
1 parent b146da6 commit 76f7645
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,12 @@ function proxyRequest(req: NextRequest, module: AppRouteModule): NextRequest {
const result = handleForceStatic(target.href, prop)
if (result !== undefined) return result
}
const value = (target as any)[prop]

return (target as any)[prop]
if (typeof value === 'function') {
return value.bind(target)
}
return value
},
set(target, prop, value) {
handleNextUrlBailout(prop)
Expand Down Expand Up @@ -320,8 +324,12 @@ function proxyRequest(req: NextRequest, module: AppRouteModule): NextRequest {
const result = handleForceStatic(target.url, prop)
if (result !== undefined) return result
}
const value = (target as any)[prop]

return (target as any)[prop]
if (typeof value === 'function') {
return value.bind(target)
}
return value
},
set(target, prop, value) {
handleReqBailout(prop)
Expand Down
75 changes: 75 additions & 0 deletions test/e2e/app-dir/app-routes/app-custom-routes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ createNextDescribe(
const meta = getRequestMeta(res.headers)
expect(meta.ping).toEqual('pong')
})

it('can read query parameters (edge)', async () => {
const res = await next.fetch('/edge/advanced/query?ping=pong')

expect(res.status).toEqual(200)
const meta = getRequestMeta(res.headers)
expect(meta.ping).toEqual('pong')
})
})

describe('response', () => {
Expand Down Expand Up @@ -203,6 +211,27 @@ createNextDescribe(
})
}

it('can handle handle a streaming request and streaming response (edge)', async () => {
const body = new Array(10).fill(JSON.stringify({ ping: 'pong' }))
let index = 0
const stream = new Readable({
read() {
if (index >= body.length) return this.push(null)

this.push(body[index] + '\n')
index++
},
})

const res = await next.fetch('/edge/advanced/body/streaming', {
method: 'POST',
body: stream,
})

expect(res.status).toEqual(200)
expect(await res.text()).toEqual(body.join('\n') + '\n')
})

it('can read a JSON encoded body', async () => {
const body = { ping: 'pong' }
const res = await next.fetch('/advanced/body/json', {
Expand All @@ -215,6 +244,18 @@ createNextDescribe(
expect(meta.body).toEqual(body)
})

it('can read a JSON encoded body (edge)', async () => {
const body = { ping: 'pong' }
const res = await next.fetch('/edge/advanced/body/json', {
method: 'POST',
body: JSON.stringify(body),
})

expect(res.status).toEqual(200)
const meta = getRequestMeta(res.headers)
expect(meta.body).toEqual(body)
})

// we can't stream a body to a function currently only stream response
if (!(global as any).isNextDeploy) {
it('can read a streamed JSON encoded body', async () => {
Expand All @@ -240,6 +281,28 @@ createNextDescribe(
})
}

it('can read a streamed JSON encoded body (edge)', async () => {
const body = { ping: 'pong' }
const encoded = JSON.stringify(body)
let index = 0
const stream = new Readable({
async read() {
if (index >= encoded.length) return this.push(null)

this.push(encoded[index])
index++
},
})
const res = await next.fetch('/edge/advanced/body/json', {
method: 'POST',
body: stream,
})

expect(res.status).toEqual(200)
const meta = getRequestMeta(res.headers)
expect(meta.body).toEqual(body)
})

it('can read the text body', async () => {
const body = 'hello, world'
const res = await next.fetch('/advanced/body/text', {
Expand All @@ -251,6 +314,18 @@ createNextDescribe(
const meta = getRequestMeta(res.headers)
expect(meta.body).toEqual(body)
})

it('can read the text body (edge)', async () => {
const body = 'hello, world'
const res = await next.fetch('/edge/advanced/body/text', {
method: 'POST',
body,
})

expect(res.status).toEqual(200)
const meta = getRequestMeta(res.headers)
expect(meta.body).toEqual(body)
})
})

describe('context', () => {
Expand Down
12 changes: 12 additions & 0 deletions test/e2e/app-dir/app-routes/app/edge/advanced/body/json/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { NextRequest } from 'next/server'
import { withRequestMeta } from '../../../../../helpers'

export const runtime = 'experimental-edge'

export async function POST(request: NextRequest) {
const body = await request.json()
return new Response('hello, world', {
status: 200,
headers: withRequestMeta({ body }),
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { NextRequest } from 'next/server'

export const runtime = 'experimental-edge'

export async function POST(request: NextRequest) {
const reader = request.body?.getReader()
if (!reader) {
return new Response(null, { status: 400, statusText: 'Bad Request' })
}

// Readable stream here is polyfilled from the Fetch API (from undici).
const stream = new ReadableStream({
async pull(controller) {
// Read the next chunk from the stream.
const { value, done } = await reader.read()
if (done) {
// Finish the stream.
return controller.close()
}

// Add the request value to the response stream.
controller.enqueue(value)
},
})

return new Response(stream, { status: 200 })
}
12 changes: 12 additions & 0 deletions test/e2e/app-dir/app-routes/app/edge/advanced/body/text/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { NextRequest } from 'next/server'
import { withRequestMeta } from '../../../../../helpers'

export const runtime = 'experimental-edge'

export async function POST(request: NextRequest) {
const body = await request.text()
return new Response('hello, world', {
status: 200,
headers: withRequestMeta({ body }),
})
}
14 changes: 14 additions & 0 deletions test/e2e/app-dir/app-routes/app/edge/advanced/query/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { withRequestMeta } from '../../../../helpers'
import { NextRequest } from 'next/server'

export const runtime = 'experimental-edge'

export async function GET(request: NextRequest): Promise<Response> {
const { searchParams } = request.nextUrl

return new Response('hello, world', {
headers: withRequestMeta({
ping: searchParams.get('ping'),
}),
})
}

0 comments on commit 76f7645

Please sign in to comment.