From 17cb1ef999139ce71eda4d63d228928a40cba1f5 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 23 Jan 2020 03:23:34 -0600 Subject: [PATCH] Fix rewriting to API routes not including query (#10223) --- .../next/next-server/server/next-server.ts | 32 ++++++++++++------- test/integration/custom-routes/next.config.js | 12 +++++++ .../custom-routes/pages/api/hello.js | 1 + .../custom-routes/test/index.test.js | 32 +++++++++++++++++++ 4 files changed, 65 insertions(+), 12 deletions(-) create mode 100644 test/integration/custom-routes/pages/api/hello.js diff --git a/packages/next/next-server/server/next-server.ts b/packages/next/next-server/server/next-server.ts index a7029431e628eda..5f4f8f2e218a627 100644 --- a/packages/next/next-server/server/next-server.ts +++ b/packages/next/next-server/server/next-server.ts @@ -561,7 +561,8 @@ export default class Server { const handled = await this.handleApiRequest( req as NextApiRequest, res as NextApiResponse, - pathname! + pathname!, + query ) if (handled) { return { finished: true } @@ -633,7 +634,8 @@ export default class Server { private async handleApiRequest( req: IncomingMessage, res: ServerResponse, - pathname: string + pathname: string, + query: ParsedUrlQuery ) { let page = pathname let params: Params | boolean = false @@ -659,15 +661,17 @@ export default class Server { const builtPagePath = await this.getPagePath(page) const pageModule = require(builtPagePath) + query = { ...query, ...params } if (!this.renderOpts.dev && this._isLikeServerless) { if (typeof pageModule.default === 'function') { + this.prepareServerlessUrl(req, query) await pageModule.default(req, res) return true } } - await apiResolver(req, res, params, pageModule, this.onErrorMiddleware) + await apiResolver(req, res, query, pageModule, this.onErrorMiddleware) return true } @@ -831,6 +835,18 @@ export default class Server { res.end(payload) } + private prepareServerlessUrl(req: IncomingMessage, query: ParsedUrlQuery) { + const curUrl = parseUrl(req.url!, true) + req.url = formatUrl({ + ...curUrl, + search: undefined, + query: { + ...curUrl.query, + ...query, + }, + }) + } + private async renderToHTMLWithComponents( req: IncomingMessage, res: ServerResponse, @@ -854,15 +870,7 @@ export default class Server { if (!isSSG) { // handle serverless if (isLikeServerless) { - const curUrl = parseUrl(req.url!, true) - req.url = formatUrl({ - ...curUrl, - search: undefined, - query: { - ...curUrl.query, - ...query, - }, - }) + this.prepareServerlessUrl(req, query) return result.Component.renderReqToHTML(req, res) } diff --git a/test/integration/custom-routes/next.config.js b/test/integration/custom-routes/next.config.js index 3bff663bc6a378e..0459f37750cb93c 100644 --- a/test/integration/custom-routes/next.config.js +++ b/test/integration/custom-routes/next.config.js @@ -55,6 +55,18 @@ module.exports = { source: '/hidden/_next/:path*', destination: '/_next/:path*', }, + { + source: '/api-hello', + destination: '/api/hello', + }, + { + source: '/api-hello-regex/(.*)', + destination: '/api/hello?name=:1', + }, + { + source: '/api-hello-param/:name', + destination: '/api/hello?name=:name', + }, ] }, async redirects() { diff --git a/test/integration/custom-routes/pages/api/hello.js b/test/integration/custom-routes/pages/api/hello.js new file mode 100644 index 000000000000000..fd03963a3a959fe --- /dev/null +++ b/test/integration/custom-routes/pages/api/hello.js @@ -0,0 +1 @@ +export default async (req, res) => res.json({ query: req.query }) diff --git a/test/integration/custom-routes/test/index.test.js b/test/integration/custom-routes/test/index.test.js index d02c75e54f71677..8b249d82e08d392 100644 --- a/test/integration/custom-routes/test/index.test.js +++ b/test/integration/custom-routes/test/index.test.js @@ -260,6 +260,23 @@ const runTests = (isDev = false) => { expect(res.headers.get('refresh')).toBe(`0;url=/`) }) + it('should handle basic api rewrite successfully', async () => { + const data = await renderViaHTTP(appPort, '/api-hello') + expect(JSON.parse(data)).toEqual({ query: {} }) + }) + + it('should handle api rewrite with un-named param successfully', async () => { + const data = await renderViaHTTP(appPort, '/api-hello-regex/hello/world') + expect(JSON.parse(data)).toEqual({ + query: { '1': 'hello/world', name: 'hello/world' }, + }) + }) + + it('should handle api rewrite with param successfully', async () => { + const data = await renderViaHTTP(appPort, '/api-hello-param/hello') + expect(JSON.parse(data)).toEqual({ query: { name: 'hello' } }) + }) + if (!isDev) { it('should output routes-manifest successfully', async () => { const manifest = await fs.readJSON( @@ -476,6 +493,21 @@ const runTests = (isDev = false) => { ), source: '/hidden/_next/:path*', }, + { + destination: '/api/hello', + regex: normalizeRegEx('^\\/api-hello$'), + source: '/api-hello', + }, + { + destination: '/api/hello?name=:1', + regex: normalizeRegEx('^\\/api-hello-regex(?:\\/(.*))$'), + source: '/api-hello-regex/(.*)', + }, + { + destination: '/api/hello?name=:name', + regex: normalizeRegEx('^\\/api-hello-param(?:\\/([^\\/]+?))$'), + source: '/api-hello-param/:name', + }, ], dynamicRoutes: [ {