Skip to content

Commit

Permalink
Merge branch 'canary' into feat/middleware-index-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
feugy committed Aug 9, 2022
2 parents 04e418f + 5d93753 commit a44eeed
Show file tree
Hide file tree
Showing 118 changed files with 555 additions and 472 deletions.
11 changes: 5 additions & 6 deletions docs/api-routes/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ description: Next.js supports API Routes, which allow you to build your API with
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes">Basic API Routes</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-middleware">API Routes with middleware</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-graphql">API Routes with GraphQL</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-rest">API Routes with REST</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors">API Routes with CORS</a></li>
Expand All @@ -31,7 +30,7 @@ export default function handler(req, res) {
For an API route to work, you need to export a function as default (a.k.a **request handler**), which then receives the following parameters:

- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage), plus some [pre-built middlewares](/docs/api-routes/api-middlewares.md)
- `req`: An instance of [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage), plus some [pre-built middlewares](/docs/api-routes/request-helpers.md)
- `res`: An instance of [http.ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse), plus some [helper functions](/docs/api-routes/response-helpers.md)

To handle different HTTP methods in an API route, you can use `req.method` in your request handler, like so:
Expand All @@ -57,17 +56,17 @@ For new projects, you can build your entire API with API Routes. If you have an

## Caveats

- API Routes [do not specify CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), meaning they are **same-origin only** by default. You can customize such behavior by wrapping the request handler with the [CORS middleware](/docs/api-routes/api-middlewares.md#connectexpress-middleware-support).
- API Routes [do not specify CORS headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS), meaning they are **same-origin only** by default. You can customize such behavior by wrapping the request handler with the [CORS request helpers](https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors).
- API Routes can't be used with [`next export`](/docs/advanced-features/static-html-export.md)

## Related

For more information on what to do next, we recommend the following sections:

<div class="card">
<a href="/docs/api-routes/api-middlewares.md">
<b>API Middlewares:</b>
<small>learn about the built-in middlewares for the request.</small>
<a href="/docs/api-routes/request-helpers.md">
<b>API Routes Request Helpers:</b>
<small>learn about the built-in helpers for the request.</small>
</a>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
---
description: API Routes provide built-in middlewares that parse the incoming request. Learn more about them here.
description: API Routes provide built-in request helpers that parse the incoming request. Learn more about them here.
---

# API Middlewares
# API Routes Request Helpers

<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-middleware">API Routes with middleware</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-middleware">API Routes Request Helpers</a></li>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors">API Routes with CORS</a></li>
</ul>
</details>

API routes provide built in middlewares which parse the incoming request (`req`). Those middlewares are:
API Routes provide built-in request helpers which parse the incoming request (`req`):

- `req.cookies` - An object containing the cookies sent by the request. Defaults to `{}`
- `req.query` - An object containing the [query string](https://en.wikipedia.org/wiki/Query_string). Defaults to `{}`
- `req.body` - An object containing the body parsed by `content-type`, or `null` if no body was sent

## Custom config

Every API route can export a `config` object to change the default configs, which are the following:
Every API Route can export a `config` object to change the default configuration, which is the following:

```js
export const config = {
Expand All @@ -32,7 +32,7 @@ export const config = {
}
```

The `api` object includes all configs available for API routes.
The `api` object includes all config options available for API Routes.

`bodyParser` is automatically enabled. If you want to consume the body as a `Stream` or with [`raw-body`](https://www.npmjs.com/package/raw-body), you can set this to `false`.

Expand Down Expand Up @@ -68,7 +68,7 @@ export const config = {
}
```

`responseLimit` is automatically enabled, warning when an API routes' response body is over 4MB.
`responseLimit` is automatically enabled, warning when an API Routes' response body is over 4MB.

If you are not using Next.js in a serverless environment, and understand the performance implications of not using a CDN or dedicated media host, you can set this limit to `false`.

Expand All @@ -91,57 +91,6 @@ export const config = {
}
```

## Connect/Express middleware support

You can also use [Connect](https://github.com/senchalabs/connect) compatible middleware.

For example, [configuring CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) for your API endpoint can be done leveraging the [cors](https://www.npmjs.com/package/cors) package.

First, install `cors`:

```bash
npm i cors
# or
yarn add cors
```

Now, let's add `cors` to the API route:

```js
import Cors from 'cors'

// Initializing the cors middleware
const cors = Cors({
methods: ['GET', 'HEAD'],
})

// Helper method to wait for a middleware to execute before continuing
// And to throw an error when an error happens in a middleware
function runMiddleware(req, res, fn) {
return new Promise((resolve, reject) => {
fn(req, res, (result) => {
if (result instanceof Error) {
return reject(result)
}

return resolve(result)
})
})
}

async function handler(req, res) {
// Run the middleware
await runMiddleware(req, res, cors)

// Rest of the API logic
res.json({ message: 'Hello Everyone!' })
}

export default handler
```

> Go to the [API Routes with CORS](https://github.com/vercel/next.js/tree/canary/examples/api-routes-cors) example to see the finished app.
## Extending the `req`/`res` objects with TypeScript

For better type-safety, it is not recommended to extend the `req` and `res` objects. Instead, use functions to work with them:
Expand Down
2 changes: 1 addition & 1 deletion docs/api-routes/response-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description: API Routes include a set of Express.js-like methods for the response to help you creating new API endpoints. Learn how it works here.
---

# Response Helpers
# API Routes Response Helpers

The [Server Response object](https://nodejs.org/api/http.html#http_class_http_serverresponse), (often abbreviated as `res`) includes a set of Express.js-like helper methods to improve the developer experience and increase the speed of creating new API endpoints.

Expand Down
2 changes: 2 additions & 0 deletions docs/basic-features/data-fetching/get-static-props.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ You should use `getStaticProps` if:
`getStaticProps` always runs on the server and never on the client. You can validate code written inside `getStaticProps` is removed from the client-side bundle [with this tool](https://next-code-elimination.vercel.app/).

- `getStaticProps` always runs during `next build`
- `getStaticProps` runs in the background when using [`fallback: true`](/docs/api-reference/data-fetching/get-static-paths#fallback-true)
- `getStaticProps` is called before initial render when using [`fallback: blocking`](/docs/api-reference/data-fetching/get-static-paths#fallback-blocking)
- `getStaticProps` runs in the background when using `revalidate`
- `getStaticProps` runs on-demand in the background when using [`revalidate()`](/docs/basic-features/data-fetching/incremental-static-regeneration.md#on-demand-revalidation)

Expand Down
6 changes: 5 additions & 1 deletion docs/basic-features/script.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ Or by using the `dangerouslySetInnerHTML` property:
```jsx
<Script
id="show-banner"
strategy="lazyOnload"
dangerouslySetInnerHTML={{
__html: `document.getElementById('banner').classList.remove('hidden')`,
}}
Expand Down Expand Up @@ -280,16 +281,19 @@ export default function Home() {
Some third-party scripts require users to run JavaScript code after the script has finished loading and every time the component is mounted (after a route navigation for example). You can execute code after the script's `load` event when it first loads and then after every subsequent component re-mount using the `onReady` property:

```jsx
import { useRef } from 'react'
import Script from 'next/script'

export default function Home() {
const mapRef = useRef()
return (
<>
<div ref={mapRef}></div>
<Script
id="google-maps"
src="https://maps.googleapis.com/maps/api/js"
onReady={() => {
new google.maps.Map(ref.current, {
new google.maps.Map(mapRef.current, {
center: { lat: -34.397, lng: 150.644 },
zoom: 8,
})
Expand Down
9 changes: 8 additions & 1 deletion docs/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@
{
"title": "API Routes",
"routes": [
{
"path": "/docs/api-routes/api-middlewares",
"redirect": {
"destination": "/docs/api-routes/request-helpers",
"permanent": true
}
},
{
"title": "Introduction",
"path": "/docs/api-routes/introduction.md"
Expand All @@ -137,7 +144,7 @@
},
{
"title": "API Middlewares",
"path": "/docs/api-routes/api-middlewares.md"
"path": "/docs/api-routes/request-helpers.md"
},
{
"title": "Response Helpers",
Expand Down
2 changes: 1 addition & 1 deletion errors/invalid-page-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,5 +115,5 @@ export const config = {}
### Useful Links

- [Enabling AMP Support](https://nextjs.org/docs/advanced-features/amp-support/introduction)
- [API Middlewares](https://nextjs.org/docs/api-routes/api-middlewares)
- [API Routes Request Helpers](https://nextjs.org/docs/api-routes/request-helpers)
- [Switchable Runtime](https://nextjs.org/docs/advanced-features/react-18/switchable-runtime)
4 changes: 4 additions & 0 deletions errors/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,10 @@
{
"title": "failed-to-fetch-devpagesmanifest",
"path": "/errors/failed-to-fetch-devpagesmanifest.md"
},
{
"title": "middleware-parse-user-agent",
"path": "/errors/middleware-parse-user-agent.md"
}
]
}
Expand Down
34 changes: 34 additions & 0 deletions errors/middleware-parse-user-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Removed parsed User Agent from Middleware API

#### Why This Error Occurred

Your application is interacting with `req.ua` which has been deprecated.

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

export function middleware(request: NextRequest) {
const viewport = request.ua.device.type === 'mobile' ? 'mobile' : 'desktop'

request.nextUrl.searchParams.set('viewport', viewport)
return NextResponse.rewrites(request.nextUrl)
}
```

#### Possible Ways to Fix It

The internal logic has been moved into a separate `userAgent` function that you can import from `next/server` and wrap your request instead.

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

export function middleware(request: NextRequest) {
const { device } = userAgent(request)
const viewport = device.type === 'mobile' ? 'mobile' : 'desktop'

request.nextUrl.searchParams.set('viewport', viewport)
return NextResponse.rewrites(request.nextUrl)
}
```
2 changes: 1 addition & 1 deletion errors/middleware-request-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#### Why This Error Occurred

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

```typescript
// middleware.ts
Expand Down
4 changes: 2 additions & 2 deletions examples/cms-wordpress/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# A statically generated blog example using Next.js and WordPress
# An Incremental Static Regeneration Blog Example Using Next.js and WordPress

This example showcases Next.js's [Static Generation](https://nextjs.org/docs/basic-features/pages) feature using [WordPress](https://wordpress.org) as the data source.
This example showcases Next.js's [Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration) feature using [WordPress](https://wordpress.org) as the data source.

## Demo

Expand Down
12 changes: 11 additions & 1 deletion examples/cms-wordpress/components/cover-image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,17 @@ import cn from 'classnames'
import Image from 'next/image'
import Link from 'next/link'

export default function CoverImage({ title, coverImage, slug }) {
interface Props {
title: string
coverImage: {
node: {
sourceUrl: string
}
}
slug?: string
}

export default function CoverImage({ title, coverImage, slug }: Props) {
const image = (
<Image
width={2000}
Expand Down
2 changes: 1 addition & 1 deletion examples/cms-wordpress/lib/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const API_URL = process.env.WORDPRESS_API_URL

async function fetchAPI(query = '', { variables } = {}) {
async function fetchAPI(query = '', { variables }: Record<string, any> = {}) {
const headers = { 'Content-Type': 'application/json' }

if (process.env.WORDPRESS_AUTH_REFRESH_TOKEN) {
Expand Down
1 change: 1 addition & 0 deletions examples/cms-wordpress/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
images: {
domains: [
process.env.WORDPRESS_API_URL.match(/(?!(w+)\.)\w*(?:\w+\.)+\w+/)[0], // Valid WP Image domain.
'0.gravatar.com',
'1.gravatar.com',
'2.gravatar.com',
'secure.gravatar.com',
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "12.2.4"
"version": "12.2.5-canary.0"
}
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@
"semver": "7.3.7",
"shell-quote": "1.7.3",
"styled-components": "5.3.3",
"styled-jsx": "link:packages/next/node_modules/styled-jsx",
"styled-jsx-plugin-postcss": "3.0.2",
"tailwindcss": "1.1.3",
"taskr": "1.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "12.2.4",
"version": "12.2.5-canary.0",
"keywords": [
"react",
"next",
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-config-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-config-next",
"version": "12.2.4",
"version": "12.2.5-canary.0",
"description": "ESLint configuration used by NextJS.",
"main": "index.js",
"license": "MIT",
Expand All @@ -9,7 +9,7 @@
"directory": "packages/eslint-config-next"
},
"dependencies": {
"@next/eslint-plugin-next": "12.2.4",
"@next/eslint-plugin-next": "12.2.5-canary.0",
"@rushstack/eslint-patch": "^1.1.3",
"@typescript-eslint/parser": "^5.21.0",
"eslint-import-resolver-node": "^0.3.6",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/eslint-plugin-next",
"version": "12.2.4",
"version": "12.2.5-canary.0",
"description": "ESLint plugin for NextJS.",
"main": "lib/index.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "12.2.4",
"version": "12.2.5-canary.0",
"main": "index.js",
"types": "index.d.ts",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-codemod/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/codemod",
"version": "12.2.4",
"version": "12.2.5-canary.0",
"license": "MIT",
"dependencies": {
"chalk": "4.1.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-env/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/env",
"version": "12.2.4",
"version": "12.2.5-canary.0",
"keywords": [
"react",
"next",
Expand Down
Loading

0 comments on commit a44eeed

Please sign in to comment.