diff --git a/packages/next/next-server/server/api-utils.ts b/packages/next/next-server/server/api-utils.ts index 76eb4095c582..8436622fa74e 100644 --- a/packages/next/next-server/server/api-utils.ts +++ b/packages/next/next-server/server/api-utils.ts @@ -56,7 +56,7 @@ export async function apiResolver( ) // Parsing of body - if (bodyParser) { + if (bodyParser && !apiReq.body) { apiReq.body = await parseBody( apiReq, config.api && config.api.bodyParser && config.api.bodyParser.sizeLimit diff --git a/test/integration/api-body-parser/pages/api/index.js b/test/integration/api-body-parser/pages/api/index.js new file mode 100644 index 000000000000..28ef9244fcef --- /dev/null +++ b/test/integration/api-body-parser/pages/api/index.js @@ -0,0 +1,5 @@ +export default ({ method, body }, res) => { + if (method === 'POST') { + res.status(200).json(body) + } +} diff --git a/test/integration/api-body-parser/server.js b/test/integration/api-body-parser/server.js new file mode 100644 index 000000000000..646c0dc3a4e6 --- /dev/null +++ b/test/integration/api-body-parser/server.js @@ -0,0 +1,28 @@ +const next = require('next') +const bodyParser = require('body-parser') +const express = require('express') + +const dev = process.env.NODE_ENV !== 'production' +const dir = __dirname +const port = process.env.PORT || 3000 + +const app = next({ dev, dir }) +const handleNextRequests = app.getRequestHandler() + +app.prepare().then(() => { + const server = express() + + server.use(bodyParser.json({ limit: '5mb' })) + + server.all('*', (req, res) => { + handleNextRequests(req, res) + }) + + server.listen(port, (err) => { + if (err) { + throw err + } + + console.log(`> Ready on http://localhost:${port}`) + }) +}) diff --git a/test/integration/api-body-parser/test/index.test.js b/test/integration/api-body-parser/test/index.test.js new file mode 100644 index 000000000000..ea90f43bdbcf --- /dev/null +++ b/test/integration/api-body-parser/test/index.test.js @@ -0,0 +1,72 @@ +/* eslint-env jest */ + +import { join } from 'path' +import { + killApp, + findPort, + launchApp, + fetchViaHTTP, + initNextServerScript, +} from 'next-test-utils' +import clone from 'clone' +import getPort from 'get-port' + +jest.setTimeout(1000 * 60 * 2) +const appDir = join(__dirname, '../') +let appPort + +let app +let server +jest.setTimeout(1000 * 60 * 2) + +const context = {} + +function runTests() { + it('should parse JSON body', async () => { + appPort = await findPort() + app = await launchApp(appDir, appPort, {}) + const data = await makeRequest() + expect(data).toEqual([{ title: 'Nextjs' }]) + killApp(app) + }) + + it('should not throw if request body is already parsed in custom middleware', async () => { + await startServer() + const data = await makeRequest() + expect(data).toEqual([{ title: 'Nextjs' }]) + killApp(server) + }) +} + +async function makeRequest() { + const data = await fetchViaHTTP(appPort, '/api', null, { + method: 'POST', + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + body: JSON.stringify([{ title: 'Nextjs' }]), + }).then((res) => res.ok && res.json()) + + return data +} + +const startServer = async (optEnv = {}, opts) => { + const scriptPath = join(appDir, 'server.js') + context.appPort = appPort = await getPort() + const env = Object.assign( + {}, + clone(process.env), + { PORT: `${appPort}` }, + optEnv + ) + + server = await initNextServerScript( + scriptPath, + /ready on/i, + env, + /ReferenceError: options is not defined/, + opts + ) +} + +runTests()