Skip to content

Commit

Permalink
Add flag to disable API warning (#11380)
Browse files Browse the repository at this point in the history
* Add flag to disable API warning

This flag is useful when you are using an external API resolver like express when defining an API route, since the native functionality doesn't realize that the API actually sent a response.

A very simple use case example https://github.com/PabloSzx/next-external-api-resolver-example

fixes #10589

* Update api-middlewares.md

Co-authored-by: Tim Neutkens <[email protected]>
  • Loading branch information
PabloSzx and timneutkens authored May 7, 2020
1 parent 63bfbff commit dac715e
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 1 deletion.
10 changes: 10 additions & 0 deletions docs/api-routes/api-middlewares.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ export const config = {
}
```

`externalResolver` is an explicit flag that tells the server that this route is being handled by an external resolver like _express_ or _connect_. Enabling this option disables warnings for unresolved requests.

```js
export const config = {
api: {
externalResolver: true,
},
}
```

## Connect/Express middleware support

You can also use [Connect](https://github.com/senchalabs/connect) compatible middleware.
Expand Down
8 changes: 7 additions & 1 deletion packages/next/next-server/server/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export async function apiResolver(
}
const config: PageConfig = resolverModule.config || {}
const bodyParser = config.api?.bodyParser !== false
const externalResolver = config.api?.externalResolver || false

// Parsing of cookies
setLazyProp({ req: apiReq }, 'cookies', getCookieParser(req))
Expand Down Expand Up @@ -70,7 +71,12 @@ export async function apiResolver(
// Call API route method
await resolver(req, res)

if (process.env.NODE_ENV !== 'production' && !isResSent(res) && !wasPiped) {
if (
process.env.NODE_ENV !== 'production' &&
!externalResolver &&
!isResSent(res) &&
!wasPiped
) {
console.warn(
`API resolved without sending a response for ${req.url}, this may result in stalled requests.`
)
Expand Down
6 changes: 6 additions & 0 deletions packages/next/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ export type PageConfig = {
* format supported by `bytes`, for example `1000`, `'500kb'` or `'3mb'`.
*/
bodyParser?: { sizeLimit?: number | string } | false
/**
* Flag to disable warning "API page resolved
* without sending a response", due to explicitly
* using an external API resolver, like express
*/
externalResolver?: true
}
env?: Array<string>
unstable_runtimeJS?: false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default (_req, res) => {
setTimeout(() => {
res.send('hello world')
}, 0)
}
11 changes: 11 additions & 0 deletions test/integration/api-support/pages/api/external-resolver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default (_req, res) => {
setTimeout(() => {
res.send('hello world')
}, 0)
}

export const config = {
api: {
externalResolver: true,
},
}
19 changes: 19 additions & 0 deletions test/integration/api-support/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,25 @@ function runTests(dev = false) {
`API resolved without sending a response for /api/test-res-pipe`
)
})

it('should show false positive warning if not using externalResolver flag', async () => {
const apiURL = '/api/external-resolver-false-positive'
const req = await fetchViaHTTP(appPort, apiURL)
expect(stderr).toContain(
`API resolved without sending a response for ${apiURL}, this may result in stalled requests.`
)
expect(await req.text()).toBe('hello world')
})

it('should not show warning if using externalResolver flag', async () => {
const startIdx = stderr.length > 0 ? stderr.length - 1 : stderr.length
const apiURL = '/api/external-resolver'
const req = await fetchViaHTTP(appPort, apiURL)
expect(stderr.substr(startIdx)).not.toContain(
`API resolved without sending a response for ${apiURL}`
)
expect(await req.text()).toBe('hello world')
})
} else {
it('should show warning with next export', async () => {
const { stdout } = await nextExport(
Expand Down

0 comments on commit dac715e

Please sign in to comment.