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

fix(#11930): rewritten api routes can correctly handle cors in dev mode #38937

Merged
merged 9 commits into from Jul 30, 2022
7 changes: 3 additions & 4 deletions packages/next/server/dev/hot-reloader.ts
Expand Up @@ -17,7 +17,7 @@ import {
import { watchCompilers } from '../../build/output'
import * as Log from '../../build/output/log'
import getBaseWebpackConfig from '../../build/webpack-config'
import { API_ROUTE, APP_DIR_ALIAS } from '../../lib/constants'
import { APP_DIR_ALIAS } from '../../lib/constants'
import { recursiveDelete } from '../../lib/recursive-delete'
import {
BLOCKED_PAGES,
Expand Down Expand Up @@ -78,9 +78,8 @@ export async function renderScriptError(
}

function addCorsSupport(req: IncomingMessage, res: ServerResponse) {
const isApiRoute = req.url!.match(API_ROUTE)
// API routes handle their own CORS headers
if (isApiRoute) {
// Only rewrite CORS handling when URL matches a hot-reloader middleware
if (!req.url!.startsWith('/__next')) {
return { preflight: false }
}

Expand Down
45 changes: 45 additions & 0 deletions test/development/api-cors-with-rewrite/index.test.ts
@@ -0,0 +1,45 @@
import { createNext } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { fetchViaHTTP } from 'next-test-utils'

describe('Rewritten API Requests should pass OPTIONS requests to the api function', () => {
let next: NextInstance

beforeAll(async () => {
next = await createNext({
files: {
'pages/api/some-endpoint.js': `
export default (req, res) => {
res.end("successfully hit some-endpoint!")
}
`,
},
nextConfig: {
rewrites: () =>
Promise.resolve({
beforeFiles: [
// Nextjs by default requires a /api prefix, let's remove that
{
source: '/:path*',
destination: '/api/:path*',
},
],
afterFiles: [],
fallback: [],
}),
},
dependencies: {},
})
})
afterAll(() => next.destroy())

it('should pass OPTIONS requests to the api function', async () => {
const res = await fetchViaHTTP(next.url, '/some-endpoint', null, {
method: 'OPTIONS',
headers: {
Origin: 'http://localhost:3000',
},
})
expect(await res.text()).toContain('successfully hit some-endpoint!')
})
})