Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Edge Functions: deprecate access to request.page #37349

Merged
merged 1 commit into from
Jun 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions errors/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@
{
"title": "returning-response-body-in-middleware",
"path": "/errors/returning-response-body-in-middleware.md"
},
{
"title": "middleware-request-page.md",
"path": "/errors/middleware-request-page.md"
}
]
}
Expand Down
61 changes: 61 additions & 0 deletions errors/middleware-request-page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Deprecated page into Middleware API

#### Why This Error Occurred

Your application is interacting with `request.page`, and it's being deprecated.

```typescript
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'

export function middleware(request: NextRequest) {
const { params } = event.request.page
const { locale, slug } = params

if (locale && slug) {
const { search, protocol, host } = request.nextUrl
const url = new URL(`${protocol}//${locale}.${host}/${slug}${search}`)
return NextResponse.redirect(url)
}
}
```

#### Possible Ways to Fix It

You can use [URLPattern](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) instead to have the same behavior:

```typescript
// middleware.ts
import { NextRequest, NextResponse } from 'next/server'

const PATTERNS = [
[
new URLPattern({ pathname: '/:locale/:slug' }),
({ pathname }) => pathname.groups,
],
]

const params = (url) => {
const input = url.split('?')[0]
let result = {}

for (const [pattern, handler] of PATTERNS) {
const patternResult = pattern.exec(input)
if (patternResult !== null && 'pathname' in patternResult) {
result = handler(patternResult)
break
}
}
return result
}

export function middleware(request: NextRequest) {
const { locale, slug } = params(request.url)

if (locale && slug) {
const { search, protocol, host } = request.nextUrl
const url = new URL(`${protocol}//${locale}.${host}/${slug}${search}`)
return NextResponse.redirect(url)
}
}
```
9 changes: 4 additions & 5 deletions packages/next/server/web/adapter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { NextMiddleware, RequestData, FetchEventResult } from './types'
import type { RequestInit } from './spec-extension/request'
import { DeprecationError } from './error'
import { DeprecationSignatureError } from './error'
import { fromNodeHeaders } from './utils'
import { NextFetchEvent } from './spec-extension/fetch-event'
import { NextRequest } from './spec-extension/request'
Expand All @@ -23,7 +23,6 @@ export async function adapter(params: {
ip: params.request.ip,
method: params.request.method,
nextConfig: params.request.nextConfig,
page: params.request.page,
},
})

Expand Down Expand Up @@ -97,14 +96,14 @@ class NextRequestHint extends NextRequest {
}

get request() {
throw new DeprecationError({ page: this.sourcePage })
throw new DeprecationSignatureError({ page: this.sourcePage })
}

respondWith() {
throw new DeprecationError({ page: this.sourcePage })
throw new DeprecationSignatureError({ page: this.sourcePage })
}

waitUntil() {
throw new DeprecationError({ page: this.sourcePage })
throw new DeprecationSignatureError({ page: this.sourcePage })
}
}
10 changes: 9 additions & 1 deletion packages/next/server/web/error.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export class DeprecationError extends Error {
export class DeprecationSignatureError extends Error {
constructor({ page }: { page: string }) {
super(`The middleware "${page}" accepts an async API directly with the form:

Expand All @@ -10,3 +10,11 @@ export class DeprecationError extends Error {
`)
}
}

export class DeprecationPageError extends Error {
constructor() {
super(`The request.page has been deprecated in favour of URLPattern.
Read more: https://nextjs.org/docs/messages/middleware-request-page
`)
}
}
6 changes: 3 additions & 3 deletions packages/next/server/web/spec-extension/fetch-event.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DeprecationError } from '../error'
import { DeprecationSignatureError } from '../error'
import { NextRequest } from './request'

const responseSymbol = Symbol('response')
Expand Down Expand Up @@ -42,7 +42,7 @@ export class NextFetchEvent extends FetchEvent {
* Read more: https://nextjs.org/docs/messages/middleware-new-signature
*/
get request() {
throw new DeprecationError({
throw new DeprecationSignatureError({
page: this.sourcePage,
})
}
Expand All @@ -53,7 +53,7 @@ export class NextFetchEvent extends FetchEvent {
* Read more: https://nextjs.org/docs/messages/middleware-new-signature
*/
respondWith() {
throw new DeprecationError({
throw new DeprecationSignatureError({
page: this.sourcePage,
})
}
Expand Down
12 changes: 2 additions & 10 deletions packages/next/server/web/spec-extension/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { NextURL } from '../next-url'
import { isBot } from '../../utils'
import { toNodeHeaders, validateURL } from '../utils'
import parseua from 'next/dist/compiled/ua-parser-js'
import { DeprecationPageError } from '../error'

import { NextCookies } from './cookies'

Expand All @@ -14,7 +15,6 @@ export class NextRequest extends Request {
cookies: NextCookies
geo: RequestData['geo']
ip?: string
page?: { name?: string; params?: { [key: string]: string | string[] } }
ua?: UserAgent | null
url: NextURL
}
Expand All @@ -27,7 +27,6 @@ export class NextRequest extends Request {
cookies: new NextCookies(this),
geo: init.geo || {},
ip: init.ip,
page: init.page,
url: new NextURL(url, {
headers: toNodeHeaders(this.headers),
nextConfig: init.nextConfig,
Expand Down Expand Up @@ -56,10 +55,7 @@ export class NextRequest extends Request {
}

public get page() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to add ts comment @deprecated notion for this? so it's known as deprecated through typing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, good point; I never did that before, let me open a new PR 🙂

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's being mentioned as deprecated in runtime but I think the text should be strikethrough.

image

not sure why that is still exported since we can't use it anymore in next12.2

and also I have a question. what will be the good replacement for this req.page.name
in my case, I want to get the dynamic routes folder name like pages/[customer]. I used to do this with req.page.name

return {
name: this[INTERNALS].page?.name,
params: this[INTERNALS].page?.params,
}
throw new DeprecationPageError()
}

public get ua() {
Expand Down Expand Up @@ -98,10 +94,6 @@ export interface RequestInit extends globalThis.RequestInit {
i18n?: I18NConfig | null
trailingSlash?: boolean
}
page?: {
name?: string
params?: { [key: string]: string | string[] }
}
}

interface UserAgent {
Expand Down
37 changes: 34 additions & 3 deletions test/integration/middleware-general/middleware.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,38 @@
/* global globalThis */
/* global globalThis, URLPattern */
import { NextRequest, NextResponse } from 'next/server'
import magicValue from 'shared-package'

const PATTERNS = [
[
new URLPattern({ pathname: '/:locale/:id' }),
({ pathname }) => ({
pathname: '/:locale/:id',
params: pathname.groups,
}),
],
[
new URLPattern({ pathname: '/:id' }),
({ pathname }) => ({
pathname: '/:id',
params: pathname.groups,
}),
],
]

const params = (url) => {
const input = url.split('?')[0]
let result = {}

for (const [pattern, handler] of PATTERNS) {
const patternResult = pattern.exec(input)
if (patternResult !== null && 'pathname' in patternResult) {
result = handler(patternResult)
break
}
}
return result
}

export async function middleware(request) {
const url = request.nextUrl

Expand Down Expand Up @@ -151,8 +182,8 @@ export async function middleware(request) {
headers: {
'req-url-basepath': request.nextUrl.basePath,
'req-url-pathname': request.nextUrl.pathname,
'req-url-params': JSON.stringify(request.page.params),
'req-url-page': request.page.name,
'req-url-params':
url.pathname !== '/static' ? JSON.stringify(params(request.url)) : '{}',
'req-url-query': request.nextUrl.searchParams.get('foo'),
'req-url-locale': request.nextUrl.locale,
},
Expand Down
32 changes: 23 additions & 9 deletions test/integration/middleware-general/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,14 @@ function tests(context, locale = '') {

it(`should validate & parse request url from any route`, async () => {
const res = await fetchViaHTTP(context.appPort, `${locale}/static`)

expect(res.headers.get('req-url-basepath')).toBe('')
expect(res.headers.get('req-url-pathname')).toBe('/static')
expect(res.headers.get('req-url-params')).not.toBe('{}')

const { pathname, params } = JSON.parse(res.headers.get('req-url-params'))
expect(pathname).toBe(undefined)
expect(params).toEqual(undefined)

expect(res.headers.get('req-url-query')).not.toBe('bar')
if (locale !== '') {
expect(res.headers.get('req-url-locale')).toBe(locale.slice(1))
Expand All @@ -216,30 +221,39 @@ function tests(context, locale = '') {

it(`should validate & parse request url from a dynamic route with params`, async () => {
const res = await fetchViaHTTP(context.appPort, `/fr/1`)

expect(res.headers.get('req-url-basepath')).toBe('')
expect(res.headers.get('req-url-pathname')).toBe('/1')
expect(res.headers.get('req-url-params')).toBe('{"id":"1"}')
expect(res.headers.get('req-url-page')).toBe('/[id]')

const { pathname, params } = JSON.parse(res.headers.get('req-url-params'))
expect(pathname).toBe('/:locale/:id')
expect(params).toEqual({ locale: 'fr', id: '1' })

expect(res.headers.get('req-url-query')).not.toBe('bar')
expect(res.headers.get('req-url-locale')).toBe('fr')
})

it(`should validate & parse request url from a dynamic route with params and no query`, async () => {
const res = await fetchViaHTTP(context.appPort, `/fr/abc123`)
expect(res.headers.get('req-url-basepath')).toBe('')
expect(res.headers.get('req-url-pathname')).toBe('/abc123')
expect(res.headers.get('req-url-params')).toBe('{"id":"abc123"}')
expect(res.headers.get('req-url-page')).toBe('/[id]')

const { pathname, params } = JSON.parse(res.headers.get('req-url-params'))
expect(pathname).toBe('/:locale/:id')
expect(params).toEqual({ locale: 'fr', id: 'abc123' })

expect(res.headers.get('req-url-query')).not.toBe('bar')
expect(res.headers.get('req-url-locale')).toBe('fr')
})

it(`should validate & parse request url from a dynamic route with params and query`, async () => {
const res = await fetchViaHTTP(context.appPort, `/abc123?foo=bar`)
expect(res.headers.get('req-url-basepath')).toBe('')
expect(res.headers.get('req-url-pathname')).toBe('/abc123')
expect(res.headers.get('req-url-params')).toBe('{"id":"abc123"}')
expect(res.headers.get('req-url-page')).toBe('/[id]')

const { pathname, params } = JSON.parse(res.headers.get('req-url-params'))

expect(pathname).toBe('/:id')
expect(params).toEqual({ id: 'abc123' })

expect(res.headers.get('req-url-query')).toBe('bar')
expect(res.headers.get('req-url-locale')).toBe('en')
})
Expand Down
2 changes: 0 additions & 2 deletions test/production/middleware-typescript/app/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ export const middleware: NextMiddleware = function (request) {
data: 'hello from middleware',
'req-url-basepath': request.nextUrl.basePath,
'req-url-pathname': request.nextUrl.pathname,
'req-url-params': JSON.stringify(request.page.params) || '',
'req-url-page': request.page.name || '',
'req-url-query': request.nextUrl.searchParams.get('foo') || '',
'req-url-locale': request.nextUrl.locale,
},
Expand Down