From 8e161e185506120a0576c429f4dc06b06223293d Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 28 Jun 2022 10:22:48 -0500 Subject: [PATCH] Middleware docs update (#38111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Initial outline added for middleware docs * Feedback changes - not included new user agent yet * edge api routes docs * middleware page some cleanup * moved api stuff to next server, added useragent * waitUntil example added * Updated env vars section * Added cookies on the request object example * fixed naming * fixed import typo * Amy feedback * Update docs/advanced-features/middleware.md Co-authored-by: Amy Burns * first commit * more fixes * re-structuring based on feedback * changes to middleware.md * updates to edge-api-routes * code typo * Update docs/advanced-features/middleware.md Co-authored-by: JJ Kasper * Update edge-api-routes.md * Update Edge Runtime API docs * Clarify API docs * Update * Update docs/advanced-features/middleware.md * Update switchable runtime docs * Update response * experimental-edge * Update docs/advanced-features/middleware.md * Add example of forwarding headers and address comments * Add proxying headers to middleware upgrade guide * Apply suggestions from code review Co-authored-by: Jeff Escalante * fix middleware directory spec * localization explanation * update detecting runtime * Update docs/advanced-features/react-18/switchable-runtime.md Co-authored-by: Balázs Orbán * fix prettier issues * table fix * Update docs/advanced-features/react-18/switchable-runtime.md Co-authored-by: Jeff Escalante * Update docs/api-routes/edge-api-routes.md Co-authored-by: Jeff Escalante * lint-fix Co-authored-by: molebox Co-authored-by: Amy Burns Co-authored-by: Ismael Rumzan Co-authored-by: Lee Robinson Co-authored-by: Balázs Orbán Co-authored-by: Jeff Escalante Co-authored-by: Ismael --- docs/advanced-features/middleware.md | 177 +++++++++++----- .../react-18/switchable-runtime.md | 63 +++++- docs/api-reference/edge-runtime.md | 177 ++++++++++------ docs/api-reference/next/server.md | 198 ++++++------------ docs/api-routes/edge-api-routes.md | 115 ++++++++++ docs/manifest.json | 21 +- errors/middleware-upgrade-guide.md | 27 ++- 7 files changed, 516 insertions(+), 262 deletions(-) create mode 100644 docs/api-routes/edge-api-routes.md diff --git a/docs/advanced-features/middleware.md b/docs/advanced-features/middleware.md index 820e6268b48a2..a80eb7ecf5991 100644 --- a/docs/advanced-features/middleware.md +++ b/docs/advanced-features/middleware.md @@ -1,95 +1,162 @@ --- -description: Learn how to use Middleware in Next.js to run code before a request is completed. +description: Learn how to use Middleware to run code before a request is completed. --- -# Middleware (Beta) +# Middleware
- Version History +Version History -| Version | Changes | -| --------- | ------------------------------------------------------------------------------------------------------- | -| `canary` | Preparing for stability, see [upgrade guide](https://nextjs.org/docs/messages/middleware-upgrade-guide) | -| `v12.0.9` | Enforce absolute URLs in Edge Runtime ([PR](https://github.com/vercel/next.js/pull/33410)) | -| `v12.0.0` | Middleware (Beta) added. | +| Version | Changes | +| --------- | ------------------------------------------------------------------------------------------ | +| `v12.2.0` | Middleware is stable | +| `v12.0.9` | Enforce absolute URLs in Edge Runtime ([PR](https://github.com/vercel/next.js/pull/33410)) | +| `v12.0.0` | Middleware (Beta) added |
-Middleware enables you to run code before a request is completed. Based on the user's incoming request, you can modify the response by rewriting, redirecting, adding headers, or even streaming HTML. +Middleware allows you to run code before a request is completed, then based on the incoming request, you can modify the response by rewriting, redirecting, adding headers, or setting cookies. -## Usage +Middleware runs _before_ cached content, so you can personalize static files and pages. Common examples of Middleware would be authentication, A/B testing, localized pages, bot protection, and more. Regarding localized pages, you can start with [i18n routing](/docs/advanced-features/i18n-routing) and implement Middleware for more advanced use cases. -1. Install the canary version of Next.js: +> **Note:** If you were using Middleware prior to `12.2`, please see the [upgrade guide](https://nextjs.org/docs/messages/middleware-upgrade-guide). -```jsx -npm install next@canary -``` +## Using Middleware + +To begin using Middleware, follow the steps below: -2. Then, create a `middleware.ts` file under your project root directory. +1. Install the latest version of Next.js: -3. Finally, export a middleware function from the `middleware.ts` file. +```bash +npm install next@latest +``` -```jsx +2. Create a `middleware.ts` (or `.js`) file at the same level as your `pages` directory +3. Export a middleware function from the `middleware.ts` file: + +```typescript // middleware.ts +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' -import type { NextRequest, NextResponse } from 'next/server' -import { areCredentialsValid } from '../lib' +// This function can be marked `async` if using `await` inside +export function middleware(request: NextRequest) { + return NextResponse.redirect(new URL('/about-2', request.url)) +} -export function middleware(req: NextRequest) { - if (areCredentialsValid(req.headers.get('authorization'))) { - return NextResponse.next() - } - return NextResponse.redirect( - new URL(`/login?from=${req.nextUrl.pathname}`, req.url) - ) +// See "Matching Paths" below to learn more +export const config = { + matcher: '/about/:path*', } ``` -In this example, we use the standard Web API Response ([MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response)). +## Matching Paths -## API +Middleware will be invoked for **every route in your project**. The following is the execution order: -Middleware is created by using a `middleware` function that lives inside a `middleware` file. Its API is based upon the native [`FetchEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent), [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response), and [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) objects. +1. `headers` from `next.config.js` +2. `redirects` from `next.config.js` +3. Middleware (`rewrites`, `redirects`, etc.) +4. `beforeFiles` (`rewrites`) from `next.config.js` +5. Filesystem routes (`public/`, `_next/static/`, Pages, etc.) +6. `afterFiles` (`rewrites`) from `next.config.js` +7. Dynamic Routes (`/blog/[slug]`) +8. `fallback` (`rewrites`) from `next.config.js` -These native Web API objects are extended to give you more control over how you manipulate and configure a response, based on the incoming requests. +There are two ways to define which paths Middleware will run on: -The function signature: +1. Custom matcher config +2. Conditional statements -```ts -import type { NextFetchEvent } from 'next/server' -import type { NextRequest } from 'next/server' +### Matcher -export type Middleware = ( - request: NextRequest, - event: NextFetchEvent -) => Promise | Response | undefined +`matcher` allows you to filter Middleware to run on specific paths. + +```js +export const config = { + matcher: '/about/:path*', +} ``` -The function can be a default export and as such, does **not** have to be named `middleware`. Though this is a convention. Also note that you only need to make the function `async` if you are running asynchronous code. +You can match a single path or multiple paths with an array syntax: + +```js +export const config = { + matcher: ['/about/:path*', '/dashboard/:path*'], +} +``` + +### Conditional Statements + +```typescript +// middleware.ts + +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export function middleware(request: NextRequest) { + if (request.nextUrl.pathname.startsWith('/about')) { + return NextResponse.rewrite(new URL('/about-2', request.url)) + } + + if (request.nextUrl.pathname.startsWith('/dashboard')) { + return NextResponse.rewrite(new URL('/dashboard/user', request.url)) + } +} +``` -Read the full [Middleware API reference](/docs/api-reference/edge-runtime.md), note [Node.js APIs are not supported in this environment](/docs/api-reference/edge-runtime.md#unsupported-apis) +## NextResponse -## Examples +The [`NextResponse`](#nextresponse) API allows you to: -Middleware can be used for anything that shares logic for a set of pages, including: +- `redirect` the incoming request to a different URL +- `rewrite` the response by displaying a given URL +- Set response cookies +- Set response headers -- [Authentication](https://github.com/vercel/examples/tree/main/edge-functions) -- [Bot protection](https://github.com/vercel/examples/tree/main/edge-functions) -- [Redirects and rewrites](https://github.com/vercel/examples/tree/main/edge-functions) -- [Handling unsupported browsers](https://github.com/vercel/examples/tree/main/edge-functions/user-agent-based-rendering) -- [Feature flags and A/B tests](https://github.com/vercel/examples/tree/main/edge-functions) -- [Advanced i18n routing requirements](https://github.com/vercel/examples/tree/main/edge-functions) +To produce a response from Middleware, you should `rewrite` to a route ([Page](/docs/basic-features/pages.md) or [Edge API Route](/docs/api-routes/edge-api-routes.md)) that produces a response. -## Execution Order +## Using Cookies -Middleware runs directly after `redirects` and `headers`, before the first filesystem lookup. This excludes `/_next` files. +The `cookies` API extends [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and allows you to `get`, `set`, and `delete` cookies. It also includes methods like [entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) and [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries). -## Deployment +```typescript +// middleware.ts +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' -Middleware uses a [strict runtime](/docs/api-reference/edge-runtime.md) that supports standard Web APIs like `fetch`. This works out of the box using `next start`, as well as on Edge platforms like Vercel, which use [Edge Functions](http://www.vercel.com/edge). +export function middleware(request: NextRequest) { + // Setting cookies on the response + const response = NextResponse.next() + response.cookies.set('vercel', 'fast') + response.cookies.set('vercel', 'fast', { path: '/test' }) + + // Getting cookies from the request + const cookie = request.cookies.get('vercel') + console.log(cookie) // => 'fast' + const allCookies = request.cookies.entries() + console.log(allCookies) // => [{ key: 'vercel', value: 'fast' }] + const { value, options } = response.cookies.getWithOptions('vercel') + console.log(value) // => 'fast' + console.log(options) // => { Path: '/test' } + + // Deleting cookies + response.cookies.delete('vercel') + response.cookies.clear() + + return response +} +``` ## Related + + diff --git a/docs/advanced-features/react-18/switchable-runtime.md b/docs/advanced-features/react-18/switchable-runtime.md index 1aaae47c768fe..1ff2a8bf247f1 100644 --- a/docs/advanced-features/react-18/switchable-runtime.md +++ b/docs/advanced-features/react-18/switchable-runtime.md @@ -1,10 +1,21 @@ # Switchable Runtime (Alpha) -By default, Next.js uses Node.js as the runtime for page rendering, including pre-rendering and server-side rendering. +Next.js has two _server runtimes_ to run your application: the **Node.js Runtime** (default) and the [**Edge Runtime**](/docs/api-reference/edge-runtime.md). When server-rendering or serving API routes, the application code will be executed in the Node.js Runtime by default; and for [Middleware](/docs/middleware.md), it will be running in the Edge Runtime. -> Note: `runtime` option only effects pages but not middleware +|   | Node (server) | Node (lambda) | Edge | +| ------------------------------------------------------------------------------------------- | ------------- | ------------- | ---------------- | +| [Cold Boot](https://vercel.com/docs/concepts/functions/conceptual-model#cold-and-hot-boots) | / | ~250ms | Instant | +| [HTTP Streaming](https://github.com/reactwg/react-18/discussions/37) | Yes | No | Yes | +| IO | All | All | `fetch` | +| Scalability | / | High | Highest | +| Security | Normal | High | High | +| Latency | Normal | Low | Lowest | +| Code Size | / | 50MB | 1MB | +| NPM Packages | All | All | A smaller subset | -If you have [React 18](/docs/advanced-features/react-18/overview) installed, there is a new experimental feature that lets you switch the page runtime between Node.js and the [Edge Runtime](/docs/api-reference/edge-runtime). Changing the runtime affects [SSR streaming](/docs/advanced-features/react-18/streaming) and [Server Components](/docs/advanced-features/react-18/server-components) features, as well. +Next.js' default runtime configuration is good for most use cases, but there’re still many reasons to change to one runtime over the other one. For example, to enable [React 18's](/docs/advanced-features/react-18/overview) [SSR streaming](/docs/advanced-features/react-18/streaming.md) feature, you need to use a runtime that is compatible with Web Streams. For API routes that rely on native Node.js APIs, they need to run with the **Node.js Runtime**. However, if an API only uses something like cookie-based authentication, using Middleware and the [**Edge Runtime**](/docs/api-reference/edge-runtime.md) will be a better choice due to its lower latency as well as better scalability. + +Starting with `12.2`, Next.js enables you to customize the runtime for each Next.js route, for both Pages and API routes. ## Global Runtime Option @@ -14,25 +25,63 @@ You can set the experimental option `runtime` to either `'nodejs'` or `'experime // next.config.js module.exports = { experimental: { - runtime: 'nodejs', + runtime: 'experimental-edge', }, } ``` This option determines which runtime should be used as the default rendering runtime for all pages. +You can detect which runtime you're using by looking at the `process.env.NEXT_RUNTIME` Environment Variable during runtime, and examining the `options.nextRuntime` variable during webpack compilation. + ## Page Runtime Option On each page, you can optionally export a `runtime` config set to either `'nodejs'` or `'experimental-edge'`: ```jsx +// pages/index.js +export default function Index () { ... } + +export function getServerSideProps() { ... } + export const config = { - runtime: 'nodejs', + runtime: 'experimental-edge', } ``` When both the per-page runtime and global runtime are set, the per-page runtime overrides the global runtime. If the per-page runtime is _not_ set, the global runtime option will be used. -You can refer to the [Switchable Next.js Runtime RFC](https://github.com/vercel/next.js/discussions/34179) for more information. +## Edge API Routes + +[Edge API Routes](/docs/api-routes/edge-api-routes.md) enable you to build high performance APIs with Next.js using the Edge Runtime. + +```typescript +export const config = { + runtime: 'experimental-edge', +} + +export default (req) => new Response('Hello world!') +``` + +## Related + + + + -**Note:** The page runtime option is not supported in [API Routes](/docs/api-routes/introduction.md) currently. + diff --git a/docs/api-reference/edge-runtime.md b/docs/api-reference/edge-runtime.md index 5958f6d2dcd79..6e77d4140e3c2 100644 --- a/docs/api-reference/edge-runtime.md +++ b/docs/api-reference/edge-runtime.md @@ -4,88 +4,134 @@ description: The Next.js Edge Runtime is based on standard Web APIs. Learn more # Edge Runtime -The Next.js Edge Runtime is based on standard Web APIs, which is used by [Middleware](/docs/middleware.md). +The Next.js Edge Runtime is based on standard Web APIs, which is used by [Middleware](/docs/middleware.md) and [Edge API Routes](/docs/api-routes/edge-api-routes.md). -## Runtime APIs - -### Globals +## Network APIs +- [`addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) +- [`Fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) +- [`FetchEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent) +- [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers) - [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) - [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) +- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) +- [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) +- [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) - [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) -### Base64 - -- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/atob): Decodes a string of data which has been encoded using base-64 encoding -- [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/btoa): Creates a base-64 encoded ASCII string from a string of binary data - -### Encoding - -- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder): Takes a stream of code points as input and emits a stream of bytes (UTF8) -- [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder): Takes a stream of bytes as input and emit a stream of code points - -### Environment - -- `process.env`: Holds an object with all environment variables for both `next dev` and `next build` in the exact same way as any other page or API in Next.js - -### Fetch - -The [Web Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) can be used from the runtime, enabling you to use Middleware as a proxy, or connect to external storage APIs - -A potential caveat to using the Fetch API in a Middleware function is latency. For example, if you have a Middleware function running a fetch request to New York, and a user accesses your site from London, the request will be resolved from the nearest Edge to the user (in this case, London), to the origin of the request, New York. There is a risk this could happen on every request, making your site slow to respond. When using the Fetch API, you _must_ make sure it does not run on every single request made. - -### Streams - -- [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream): Consists of a pair of streams: a writable stream known as its writable side, and a readable stream, known as its readable side. Writes to the writable side, result in new data being made available for reading from the readable side. Support for web streams is quite limited at the moment, although it is more extended in the development environment -- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream): A readable stream of byte data -- [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream): A standard abstraction for writing streaming data to a destination, known as a sink - -### Timers - -- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval): Schedules a function to execute every time a given number of milliseconds elapses -- [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval): Cancels the repeated execution set using `setInterval()` -- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout): Schedules a function to execute in a given amount of time -- [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout): Cancels the delayed execution set using `setTimeout()` - -### Web - -- [`Headers`](https://developer.mozilla.org/en-US/docs/Web/API/Headers): A [WHATWG](https://whatwg.org/) implementation of the headers API -- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL): A WHATWG implementation of the URL API. -- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams): A WHATWG implementation of `URLSearchParams` - -### Crypto - -- [`Crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto): The `Crypto` interface represents basic cryptography features available in the current context -- [`crypto.randomUUID`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID): Lets you generate a v4 UUID using a cryptographically secure random number generator -- [`crypto.getRandomValues`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues): Lets you get cryptographically strong random values -- [`crypto.subtle`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle): A read-only property that returns a [SubtleCrypto](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) which can then be used to perform low-level cryptographic operations - -### Logging - -- [`console.debug`](https://developer.mozilla.org/en-US/docs/Web/API/console/debug): Outputs a message to the console with the log level debug -- [`console.info`](https://developer.mozilla.org/en-US/docs/Web/API/console/info): Informative logging of information. You may use string substitution and additional arguments with this method -- [`console.clear`](https://developer.mozilla.org/en-US/docs/Web/API/console/clear): Clears the console -- [`console.dir`](https://developer.mozilla.org/en-US/docs/Web/API/console/dir): Displays an interactive listing of the properties of a specified JavaScript object -- [`console.count`](https://developer.mozilla.org/en-US/docs/Web/API/console/count): Log the number of times this line has been called with the given label -- [`console.time`](https://developer.mozilla.org/en-US/docs/Web/API/console/time): Starts a timer with a name specified as an input parameter +## Encoding APIs + +- [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) +- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) +- [`atob`](https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/atob) +- [`btoa`](https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa) + +## Web Stream APIs + +- [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) +- [`ReadableStreamBYOBReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamBYOBReader) +- [`ReadableStreamDefaultReader`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader) +- [`TransformStream`](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) +- [`WritableStream`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStream) +- [`WritableStreamDefaultWriter`](https://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter) + +## Web Crypto APIs + +- [`crypto`](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) +- [`CryptoKey`](https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey) +- [`SubtleCrypto`](https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto) + +## Web Standards APIs + +- [`structuredClone`](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm) +- [`URLPattern`](https://developer.mozilla.org/en-US/docs/Web/API/URLPattern) +- [`Web Cache`](https://developer.mozilla.org/en-US/docs/Web/API/Cache) + +## V8 Primitives + +- [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) +- [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) +- [`Atomics`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics) +- [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) +- [`BigInt64Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array) +- [`BigUint64Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array) +- [`Boolean`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) +- [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval) +- [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout) +- [`console`](https://developer.mozilla.org/en-US/docs/Web/API/Console) +- [`DataView`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView) +- [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) +- [`decodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURI) +- [`decodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent) +- [`encodeURI`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI) +- [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) +- [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) +- [`EvalError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/EvalError) +- [`Float32Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array) +- [`Float64Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array) +- [`Function`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) +- [`Infinity`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity) +- [`Int8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array) +- [`Int16Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array) +- [`Int32Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array) +- [`Intl`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) +- [`isFinite`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite) +- [`isNaN`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) +- [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) +- [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) +- [`Math`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) +- [`Number`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) +- [`Object`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object) +- [`parseFloat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) +- [`parseInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) +- [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) +- [`Proxy`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) +- [`RangeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RangeError) +- [`ReferenceError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ReferenceError) +- [`Reflect`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect) +- [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) +- [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) +- [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval) +- [`setTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout) +- [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer) +- [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) +- [`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) +- [`SyntaxError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SyntaxError) +- [`TextDecoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder) +- [`TextEncoder`](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) +- [`TypeError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError) +- [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) +- [`Uint8ClampedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray) +- [`Uint16Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array) +- [`Uint32Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array) +- [`URIError`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/URIError) +- [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) +- [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) +- [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) +- [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) +- [`WebAssembly`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly) + +## Environment Variables + +You can use `process.env` to access [Environment Variables](/docs/basic-features/environment-variables.md) for both `next dev` and `next build`. ## Unsupported APIs The Edge Runtime has some restrictions including: - Native Node.js APIs **are not supported**. For example, you can't read or write to the filesystem -- Node Modules _can_ be used, as long as they implement ES Modules and do not use any native Node.js APIs +- `node_modules` _can_ be used, as long as they implement ES Modules and do not use native Node.js APIs - Calling `require` directly is **not allowed**. Use ES Modules instead The following JavaScript language features are disabled, and **will not work:** -- [`eval`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval): Evaluates JavaScript code represented as a string -- [`new Function(evalString)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function): Creates a new function with the code provided as an argument +- `eval`: Evaluates JavaScript code represented as a string +- `new Function(evalString)`: Creates a new function with the code provided as an argument ## Related
- + Middleware Run code before a request is completed. @@ -97,3 +143,10 @@ The following JavaScript language features are disabled, and **will not work:** Learn more about the supported APIs for Middleware.
+ + diff --git a/docs/api-reference/next/server.md b/docs/api-reference/next/server.md index 860a60b521172..11b902ea4f061 100644 --- a/docs/api-reference/next/server.md +++ b/docs/api-reference/next/server.md @@ -1,48 +1,38 @@ --- -description: Use Middleware to run code before a request is completed. +description: Learn about the server-only helpers for Middleware and Edge API Routes. --- # next/server -The `next/server` module provides several exports for server-only helpers, such as [Middleware](/docs/middleware.md). - -## NextMiddleware - -Middleware is created by using a `middleware` function that lives inside a `middleware` file. The Middleware API is based upon the native [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request), [`FetchEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent), and [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) objects. - -These native Web API objects are extended to give you more control over how you manipulate and configure a response, based on the incoming requests. - -The function signature is defined as follows: - -```typescript -type NextMiddlewareResult = NextResponse | Response | null | undefined - -type NextMiddleware = ( - request: NextRequest, - event: NextFetchEvent -) => NextMiddlewareResult | Promise -``` - -It can be imported from `next/server` with the following: - -```typescript -import type { NextMiddleware } from 'next/server' -``` - -The function can be a default export and as such, does **not** have to be named `middleware`. Though this is a convention. Also note that you only need to make the function `async` if you are running asynchronous code. +`next/server` provides server-only helpers for use in [Middleware](/docs/middleware.md) and [Edge API Routes](/docs/api-routes/edge-api-routes.md). ## NextRequest The `NextRequest` object is an extension of the native [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) interface, with the following added methods and properties: -- `cookies` - A [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) with cookies from the `Request` -- `nextUrl` - Includes an extended, parsed, URL object that gives you access to Next.js specific properties such as `pathname`, `basePath`, `trailingSlash` and `i18n` -- `ip` - (Optional) Has the IP address of the `Request`, if provided by your hosting platform -- `geo` - (Optional) Has the geo location from the `Request`, if provided by your hosting platform +- `cookies` - A [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) with cookies from the `Request`. See [Using cookies in Edge Middleware](#using-cookies-in-edge-middleware) +- `nextUrl`: Includes an extended, parsed, URL object that gives you access to Next.js specific properties such as `pathname`, `basePath`, `trailingSlash` and `i18n`. Includes the following properties: + - `basePath` (`string`) + - `buildId` (`string || undefined`) + - `defaultLocale` (`string || undefined`) + - `domainLocale` + - `defaultLocale`: (`string`) + - `domain`: (`string`) + - `http`: (`boolean || undefined`) + - `locales`: (`string[] || undefined`) + - `locale` (`string || undefined`) + - `url` (`URL`) +- `ip`: (`string || undefined`) - Has the IP address of the `Request`. This information is provided by your hosting platform. +- `geo` - Has the geographic location from the `Request`. This information is provided by your hosting platform. Includes the following properties: + - `city` (`string || undefined`) + - `country` (`string || undefined`) + - `region` (`string || undefined`) + - `latitude` (`string || undefined`) + - `longitude` (`string || undefined`) You can use the `NextRequest` object as a direct replacement for the native `Request` interface, giving you more control over how you manipulate the request. -`NextRequest` is fully typed and can be imported from `next/server`. +`NextRequest` can be imported from `next/server`: ```typescript import type { NextRequest } from 'next/server' @@ -52,9 +42,25 @@ import type { NextRequest } from 'next/server' The `NextFetchEvent` object extends the native [`FetchEvent`](https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent) object, and includes the [`waitUntil()`](https://developer.mozilla.org/en-US/docs/Web/API/ExtendableEvent/waitUntil) method. -The `waitUntil()` method can be used to prolong the execution of the function, after the response has been sent. In practice this means that you can send a response, then continue the function execution if you have other background work to make. +The `waitUntil()` method can be used to prolong the execution of the function if you have other background work to make. -The `event` object is fully typed and can be imported from `next/server`. +```typescript +import { NextResponse } from 'next/server' +import type { NextFetchEvent, NextRequest } from 'next/server' + +export async function middleware(req: NextRequest, event: NextFetchEvent) { + event.waitUntil( + fetch('https://my-analytics-platform.com', { + method: 'POST', + body: JSON.stringify({ pathname: req.nextUrl.pathname }), + }) + ) + + return NextResponse.next() +} +``` + +The `NextFetchEvent` object can be imported from `next/server`: ```typescript import type { NextFetchEvent } from 'next/server' @@ -64,31 +70,13 @@ import type { NextFetchEvent } from 'next/server' The `NextResponse` class extends the native [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) interface, with the following: -### Public methods +### Public Methods Public methods are available on an instance of the `NextResponse` class. Depending on your use case, you can create an instance and assign to a variable, then access the following public methods: -- `cookies` - The `Cookies` API extends [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), including methods like [entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) and [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries). +- `cookies` - A [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) with the cookies in the `Response` -```typescript -export function middleware() { - const response = new NextResponse() - // set a cookie - response.cookies.set('vercel', 'fast') - // set another cookie with options - response.cookies.set('nextjs', 'awesome', { path: '/test' }) - // get all the details of a cookie - const { value, options } = response.cookies.getWithOptions('vercel') - console.log(value) // => 'fast' - console.log(options) // => { Path: '/test' } - // deleting a cookie will mark it as expired - response.cookies.delete('vercel') - // clear all cookies means mark all of them as expired - response.cookies.clear() -} -``` - -### Static methods +### Static Methods The following static methods are available on the `NextResponse` class directly: @@ -96,70 +84,34 @@ The following static methods are available on the `NextResponse` class directly: - `rewrite()` - Returns a `NextResponse` with a rewrite set - `next()` - Returns a `NextResponse` that will continue the middleware chain -```typescript -import { NextResponse } from 'next/server' -import type { NextRequest } from 'next/server' - -export function middleware(req: NextRequest) { - // if the request is coming from New York, redirect to the home page - if (req.geo.city === 'New York') { - return NextResponse.redirect('/home') - // if the request is coming from London, rewrite to a special page - } else if (req.geo.city === 'London') { - return NextResponse.rewrite('/not-home') - } - - return NextResponse.next() -} -``` - -All methods above return a `NextResponse` object that only takes effect if it's returned in the middleware function. - -`NextResponse` is fully typed and can be imported from `next/server`. +The use the methods above, **you must return the `NextResponse` object** returned. `NextResponse` can be imported from `next/server`: ```typescript import { NextResponse } from 'next/server' ``` -### Setting the cookie before a redirect - -In order to set the `cookie` _before_ a redirect, you can create an instance of `NextResponse`, then access the `cookie` method on the instance, before returning the response. - -Note that there is a [Chrome bug](https://bugs.chromium.org/p/chromium/issues/detail?id=696204) which means the entire redirect chain **must** be from the same origin, if they are from different origins, then the `cookie` might be missing until a refresh. - -```typescript -import { NextResponse } from 'next/server' -import type { NextRequest } from 'next/server' - -export function middleware(req: NextRequest) { - const res = NextResponse.redirect('/') // creates an actual instance - res.cookies.set('hello', 'world') // can be called on an instance - return res -} -``` - ## userAgent The `userAgent` helper allows you to interact with the user agent object from the request. It is abstracted from the native `Request` object, and is an opt in feature. It has the following properties: -- `isBot`: Whether the request comes from a known bot +- `isBot`: (`boolean`) Whether the request comes from a known bot - `browser` - - `name`: The name of the browser, or `undefined` - - `version`: The version of the browser, determined dynamically, or `undefined` + - `name`: (`string || undefined`) The name of the browser + - `version`: (`string || undefined`) The version of the browser, determined dynamically - `device` - - `model`: The model of the device, determined dynamically, or `undefined` - - `type`: The type of the browser, can be one of the following values: `console`, `mobile`, `tablet`, `smarttv`, `wearable`, `embedded`, or `undefined` - - `vendor`: The vendor of the device, determined dynamically, or `undefined` + - `model`: (`string || undefined`) The model of the device, determined dynamically + - `type`: (`string || undefined`) The type of the browser, can be one of the following values: `console`, `mobile`, `tablet`, `smarttv`, `wearable`, `embedded`, or `undefined` + - `vendor`: (`string || undefined`) The vendor of the device, determined dynamically - `engine` - - `name`: The name of the browser engine, could be one of the following values: `Amaya`, `Blink`, `EdgeHTML`, `Flow`, `Gecko`, `Goanna`, `iCab`, `KHTML`, `Links`, `Lynx`, `NetFront`, `NetSurf`, `Presto`, `Tasman`, `Trident`, `w3m`, `WebKit` or `undefined` - - `version`: The version of the browser engine, determined dynamically, or `undefined` + - `name`: (`string || undefined`) The name of the browser engine, could be one of the following values: `Amaya`, `Blink`, `EdgeHTML`, `Flow`, `Gecko`, `Goanna`, `iCab`, `KHTML`, `Links`, `Lynx`, `NetFront`, `NetSurf`, `Presto`, `Tasman`, `Trident`, `w3m`, `WebKit` or `undefined` + - `version`: (`string || undefined`) The version of the browser engine, determined dynamically, or `undefined` - `os` - - `name`: The name of the OS, could be `undefined` - - `version`: The version of the OS, determined dynamically, or `undefined` + - `name`: (`string || undefined`) The name of the OS, could be `undefined` + - `version`: (`string || undefined`) The version of the OS, determined dynamically, or `undefined` - `cpu` - - `architecture`: The architecture of the CPU, could be one of the following values: `68k`, `amd64`, `arm`, `arm64`, `armhf`, `avr`, `ia32`, `ia64`, `irix`, `irix64`, `mips`, `mips64`, `pa-risc`, `ppc`, `sparc`, `sparc64` or `undefined` + - `architecture`: (`string || undefined`) The architecture of the CPU, could be one of the following values: `68k`, `amd64`, `arm`, `arm64`, `armhf`, `avr`, `ia32`, `ia64`, `irix`, `irix64`, `mips`, `mips64`, `pa-risc`, `ppc`, `sparc`, `sparc64` or `undefined` -`userAgent` is fully typed and can be imported from `next/server`: +`userAgent` can be imported from `next/server`: ```typescript import { userAgent } from 'next/server' @@ -177,7 +129,9 @@ export function middleware(request: NextRequest) { } ``` -### Why does redirect use 307 and 308? +## FAQ + +### Why does `redirect` use 307 and 308? When using `redirect()` you may notice that the status codes used are `307` for a temporary redirect, and `308` for a permanent redirect. While traditionally a `302` was used for a temporary redirect, and a `301` for a permanent redirect, many browsers changed the request method of the redirect, from a `POST` to `GET` request when using a `302`, regardless of the origins request method. @@ -196,35 +150,13 @@ If you want to cause a `GET` response to a `POST` request, use `303`. ### How do I access Environment Variables? -`process.env` can be used to access [Environment Variables](/docs/basic-features/environment-variables.md) from Middleware. These are evaluated at build time, so only environment variables _actually_ used will be included. - -Any variables in `process.env` must be accessed directly, and **cannot** be destructured: - -```typescript -// Accessed directly, and not destructured works. process.env.NODE_ENV is `"development"` or `"production"` -console.log(process.env.NODE_ENV) -// This will not work -const { NODE_ENV } = process.env -// NODE_ENV is `undefined` -console.log(NODE_ENV) -// process.env is `{}` -console.log(process.env) -``` - -### The body limitation - -When using middlewares, it is not permitted to change the response body: you can only set responses headers. -Returning a body from a middleware function will issue an `500` server error with an explicit response message. - -The `NextResponse` API (which eventually is tweaking response headers) allows you to: - -- redirect the incoming request to a different url -- rewrite the response by displaying a given url -- set response cookies -- set response headers +`process.env` can be used to access [Environment Variables](/docs/basic-features/environment-variables.md) from Edge Middleware. They are evaluated during `next build`: -These are solid tools to implement cases such as A/B testing, authentication, feature flags, bot protection... -A middleware with the ability to change the response's body would bypass Next.js routing logic. +| Works | Does **not** work | +| ------------------------------------------------------------ | ------------------------------------------ | +| `console.log(process.env.MY_ENV_VARIABLE)` | `const getEnv = name => process.env[name]` | +| `const { MY_ENV_VARIABLE } = process.env` | | +| `const { "MY-ENV-VARIABLE": MY_ENV_VARIABLE } = process.env` | | ## Related diff --git a/docs/api-routes/edge-api-routes.md b/docs/api-routes/edge-api-routes.md new file mode 100644 index 0000000000000..571f19879dab3 --- /dev/null +++ b/docs/api-routes/edge-api-routes.md @@ -0,0 +1,115 @@ +--- +description: Edge API Routes enable you to build high performance APIs directly inside your Next.js application. +--- + +# Edge API Routes (Beta) + +Edge API Routes enable you to build high performance APIs with Next.js. Using the [Edge Runtime](/docs/api-reference/edge-runtime.md), they are often faster than Node.js-based API Routes. This performance improvement does come with [constraints](/docs/api-reference/edge-runtime.md#unsupported-apis), like not having access to native Node.js APIs. Instead, Edge API Routes are built on standard Web APIs. + +Any file inside the folder `pages/api` is mapped to `/api/*` and will be treated as an API endpoint instead of a page. They are server-side only bundles and won't increase your client-side bundle size. + +## Examples + +### Basic + +```typescript +export const config = { + runtime: 'experimental-edge', +} + +export default (req) => new Response('Hello world!') +``` + +### JSON Response + +```typescript +import type { NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler(req: NextRequest) { + return new Response( + JSON.stringify({ + name: 'Jim Halpert', + }), + { + status: 200, + headers: { + 'content-type': 'application/json', + }, + } + ) +} +``` + +### Cache-Control + +```typescript +import type { NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler(req: NextRequest) { + return new Response( + JSON.stringify({ + name: 'Jim Halpert', + }), + { + status: 200, + headers: { + 'content-type': 'application/json', + 'cache-control': 'public, s-maxage=1200, stale-while-revalidate=600', + }, + } + ) +} +``` + +### Query Parameters + +```typescript +import type { NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler(req: NextRequest) { + const { searchParams } = new URL(req.url) + const email = searchParams.get('email') + return new Response(email) +} +``` + +### Forwarding Headers + +```typescript +import { type NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler(req: NextRequest) { + const authorization = req.cookies.get('authorization') + return fetch('https://backend-api.com/api/protected', { + method: req.method, + headers: { + authorization, + }, + redirect: 'manual', + }) +} +``` + +## Differences between API Routes + +Edge API Routes use the [Edge Runtime](/docs/api-reference/edge-runtime.md), whereas API Routes use the [Node.js runtime](/docs/advanced-features/react-18/switchable-runtime.md). + +Edge API Routes can [stream responses](/docs/api-reference/edge-runtime.md#web-stream-apis) from the server and run _after_ cached files (e.g. HTML, CSS, JavaScript) have been accessed. Server-side streaming can help improve performance with faster [Time To First Byte (TTFB)](https://web.dev/ttfb/). + +View the [supported APIs](/docs/api-reference/edge-runtime.md) and [unsupported APIs](/docs/api-reference/edge-runtime.md#unsupported-apis) for the Edge Runtime. diff --git a/docs/manifest.json b/docs/manifest.json index 8915c6ab8ef19..84bdbdfb6335e 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -4,7 +4,10 @@ "title": "Documentation", "heading": true, "routes": [ - { "title": "Getting Started", "path": "/docs/getting-started.md" }, + { + "title": "Getting Started", + "path": "/docs/getting-started.md" + }, { "title": "Basic Features", "open": true, @@ -139,6 +142,10 @@ { "title": "Response Helpers", "path": "/docs/api-routes/response-helpers.md" + }, + { + "title": "Edge API Routes (Beta)", + "path": "/docs/api-routes/edge-api-routes.md" } ] }, @@ -271,7 +278,7 @@ "path": "/docs/advanced-features/measuring-performance.md" }, { - "title": "Middleware (Beta)", + "title": "Middleware", "path": "/docs/advanced-features/middleware.md" }, { @@ -356,14 +363,20 @@ } ] }, - { "title": "FAQ", "path": "/docs/faq.md" } + { + "title": "FAQ", + "path": "/docs/faq.md" + } ] }, { "title": "API Reference", "heading": true, "routes": [ - { "title": "CLI", "path": "/docs/api-reference/cli.md" }, + { + "title": "CLI", + "path": "/docs/api-reference/cli.md" + }, { "title": "Create Next App", "path": "/docs/api-reference/create-next-app.md" diff --git a/errors/middleware-upgrade-guide.md b/errors/middleware-upgrade-guide.md index c461103f616f3..0acd9a6706c2e 100644 --- a/errors/middleware-upgrade-guide.md +++ b/errors/middleware-upgrade-guide.md @@ -84,7 +84,7 @@ export function middleware(request: NextRequest) { ### Summary of changes -- Middleware can no longer respond with a body +- Middleware can no longer produce a response body - If your Middleware _does_ respond with a body, a runtime error will be thrown - Migrate to using `rewrite`/`redirect` to pages/APIs handling a response @@ -144,6 +144,31 @@ export function middleware(request: NextRequest) { } ``` +#### Edge API Routes + +If you were previously using Middleware to forward headers to an external API, you can now use [Edge API Routes](/docs/api-routes/edge-api-routes): + +```typescript +// pages/api/proxy.ts + +import { type NextRequest } from 'next/server' + +export const config = { + runtime: 'experimental-edge', +} + +export default async function handler(req: NextRequest) { + const authorization = req.cookies.get('authorization') + return fetch('https://backend-api.com/api/protected', { + method: req.method, + headers: { + authorization, + }, + redirect: 'manual', + }) +} +``` + ## Cookies API Revamped ### Summary of changes