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

docs: Update Route Handlers docs for dynamic #66010

Merged
merged 2 commits into from
May 21, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@ Route Handlers allow you to create custom request handlers for a given route usi
Route Handlers are defined in a [`route.js|ts` file](/docs/app/api-reference/file-conventions/route) inside the `app` directory:

```ts filename="app/api/route.ts" switcher
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET(request: Request) {}
```

```js filename="app/api/route.js" switcher
export const dynamic = 'force-dynamic' // defaults to auto
export async function GET(request) {}
```

Expand All @@ -49,13 +47,11 @@ In addition to supporting native [Request](https://developer.mozilla.org/docs/We

### Caching

Route Handlers are dynamic by default as of Next.js v15. To opt-in to caching for GET requests in route handlers you can specify via the following config:
Route Handlers are dynamic by default as of Next.js v15. To opt-in to caching for `GET` requests, you can use the following config:

```ts filename="app/items/route.ts" switcher
// opt in to caching the route handler
export const dynamic = 'force-static' // or 'error'
// or
export const revalidate = false // or a value > 0

export async function GET() {
const res = await fetch('https://data.mongodb-api.com/...', {
Expand Down Expand Up @@ -86,87 +82,6 @@ export async function GET() {

> **TypeScript Warning:** `Response.json()` is only valid from TypeScript 5.2. If you use a lower TypeScript version, you can use [`NextResponse.json()`](/docs/app/api-reference/functions/next-response#json) for typed responses instead.

### Opting out of caching

You can opt out of caching by:

- Using the `Request` object with the `GET` method.
- Using any of the other HTTP methods.
- Using [Dynamic Functions](#dynamic-functions) like `cookies` and `headers`.
- The [Segment Config Options](#segment-config-options) manually specifies dynamic mode.

For example:

```ts filename="app/products/api/route.ts" switcher
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
const res = await fetch(`https://data.mongodb-api.com/product/${id}`, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY!,
},
})
const product = await res.json()

return Response.json({ product })
}
```

```js filename="app/products/api/route.js" switcher
export async function GET(request) {
const { searchParams } = new URL(request.url)
const id = searchParams.get('id')
const res = await fetch(`https://data.mongodb-api.com/product/${id}`, {
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
})
const product = await res.json()

return Response.json({ product })
}
```

Similarly, the `POST` method will cause the Route Handler to be evaluated dynamically.

```ts filename="app/items/route.ts" switcher
export async function POST() {
const res = await fetch('https://data.mongodb-api.com/...', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY!,
},
body: JSON.stringify({ time: new Date().toISOString() }),
})

const data = await res.json()

return Response.json(data)
}
```

```js filename="app/items/route.js" switcher
export async function POST() {
const res = await fetch('https://data.mongodb-api.com/...', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'API-Key': process.env.DATA_API_KEY,
},
body: JSON.stringify({ time: new Date().toISOString() }),
})

const data = await res.json()

return Response.json(data)
}
```

> **Good to know**: Like API Routes, Route Handlers can be used for cases like handling form submissions. A new abstraction for [handling forms and mutations](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) that integrates deeply with React is being worked on.

### Route Resolution

You can consider a `route` the lowest level routing primitive.
Expand Down Expand Up @@ -562,8 +477,6 @@ Since `formData` data are all strings, you may want to use [`zod-form-data`](htt
You can set CORS headers for a specific Route Handler using the standard Web API methods:

```ts filename="app/api/route.ts" switcher
export const dynamic = 'force-dynamic' // defaults to auto

export async function GET(request: Request) {
return new Response('Hello, Next.js!', {
status: 200,
Expand All @@ -577,8 +490,6 @@ export async function GET(request: Request) {
```

```js filename="app/api/route.js" switcher
export const dynamic = 'force-dynamic' // defaults to auto

export async function GET(request) {
return new Response('Hello, Next.js!', {
status: 200,
Expand Down Expand Up @@ -641,8 +552,6 @@ Notably, unlike API Routes with the Pages Router, you do not need to use `bodyPa
You can use Route Handlers to return non-UI content. Note that [`sitemap.xml`](/docs/app/api-reference/file-conventions/metadata/sitemap#generating-a-sitemap-using-code-js-ts), [`robots.txt`](/docs/app/api-reference/file-conventions/metadata/robots#generate-a-robots-file), [`app icons`](/docs/app/api-reference/file-conventions/metadata/app-icons#generate-icons-using-code-js-ts-tsx), and [open graph images](/docs/app/api-reference/file-conventions/metadata/opengraph-image) all have built-in support.

```ts filename="app/rss.xml/route.ts" switcher
export const dynamic = 'force-dynamic' // defaults to auto

export async function GET() {
return new Response(
`<?xml version="1.0" encoding="UTF-8" ?>
Expand All @@ -665,8 +574,6 @@ export async function GET() {
```

```js filename="app/rss.xml/route.js" switcher
export const dynamic = 'force-dynamic' // defaults to auto

export async function GET() {
return new Response(`<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
Expand Down
9 changes: 5 additions & 4 deletions docs/02-app/02-api-reference/02-file-conventions/route.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export async function PATCH(request) {}
export async function OPTIONS(request) {}
```

> **Good to know**: Route Handlers are only available inside the `app` directory. You **do not** need to use API Routes (`pages`) and Route Handlers (`app`) together, as Route Handlers should be able to handle all use cases.
> **Good to know**: Route Handlers are only available inside the App Router. You **do not** need to use API Routes (`pages`) and Route Handlers (`app`) together, as Route Handlers should be able to handle all use cases.

## Parameters

Expand Down Expand Up @@ -87,6 +87,7 @@ Route Handlers can extend the Web Response API by returning a `NextResponse` obj

## Version History

| Version | Changes |
| --------- | ------------------------------ |
| `v13.2.0` | Route handlers are introduced. |
| Version | Changes |
| --------- | ------------------------------------------------------------------------- |
| `v15.0.0` | The default caching for `GET` handlers was changed from static to dynamic |
| `v13.2.0` | Route Handlers are introduced. |