Skip to content

Commit

Permalink
fix(nextjs): Handle CJS API route exports (#5865)
Browse files Browse the repository at this point in the history
  • Loading branch information
lforst committed Oct 3, 2022
1 parent 92dd0ed commit b7c0e54
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 6 deletions.
27 changes: 21 additions & 6 deletions packages/nextjs/src/config/templates/apiProxyLoaderTemplate.ts
Expand Up @@ -16,14 +16,29 @@ import type { PageConfig } from 'next';
// multiple versions of next. See note in `wrappers/types` for more.
import type { NextApiHandler } from '../wrappers';

type NextApiModule = {
default: NextApiHandler;
config?: PageConfig;
};
type NextApiModule = (
| {
// ESM export
default?: NextApiHandler;
}
// CJS export
| NextApiHandler
) & { config?: PageConfig };

const userApiModule = origModule as NextApiModule;

const maybeWrappedHandler = userApiModule.default;
// Default to undefined. It's possible for Next.js users to not define any exports/handlers in an API route. If that is
// the case Next.js wil crash during runtime but the Sentry SDK should definitely not crash so we need tohandle it.
let userProvidedHandler = undefined;

if ('default' in userApiModule && typeof userApiModule.default === 'function') {
// Handle when user defines via ESM export: `export default myFunction;`
userProvidedHandler = userApiModule.default;
} else if (typeof userApiModule === 'function') {
// Handle when user defines via CJS export: "module.exports = myFunction;"
userProvidedHandler = userApiModule;
}

const origConfig = userApiModule.config || {};

// Setting `externalResolver` to `true` prevents nextjs from throwing a warning in dev about API routes resolving
Expand All @@ -38,7 +53,7 @@ export const config = {
},
};

export default Sentry.withSentryAPI(maybeWrappedHandler, '__ROUTE__');
export default userProvidedHandler ? Sentry.withSentryAPI(userProvidedHandler, '__ROUTE__') : undefined;

// Re-export anything exported by the page module we're wrapping. When processing this code, Rollup is smart enough to
// not include anything whose name matchs something we've explicitly exported above.
Expand Down
@@ -0,0 +1,7 @@
import { NextApiRequest, NextApiResponse } from 'next';

const handler = async (_req: NextApiRequest, res: NextApiResponse): Promise<void> => {
res.status(200).json({ success: true });
};

module.exports = handler;
@@ -0,0 +1,7 @@
import { NextApiRequest, NextApiResponse } from 'next';

const handler = async (_req: NextApiRequest, res: NextApiResponse): Promise<void> => {
res.status(200).json({ success: true });
};

module.exports = handler;
55 changes: 55 additions & 0 deletions packages/nextjs/test/integration/test/server/cjsApiEndpoints.js
@@ -0,0 +1,55 @@
const assert = require('assert');

const { sleep } = require('../utils/common');
const { getAsync, interceptTracingRequest } = require('../utils/server');

module.exports = async ({ url: urlBase, argv }) => {
const unwrappedRoute = '/api/withSentryAPI/unwrapped/cjsExport';
const interceptedUnwrappedRequest = interceptTracingRequest(
{
contexts: {
trace: {
op: 'http.server',
status: 'ok',
tags: { 'http.status_code': '200' },
},
},
transaction: `GET ${unwrappedRoute}`,
type: 'transaction',
request: {
url: `${urlBase}${unwrappedRoute}`,
},
},
argv,
'unwrapped CJS route',
);
const responseUnwrapped = await getAsync(`${urlBase}${unwrappedRoute}`);
assert.equal(responseUnwrapped, '{"success":true}');

const wrappedRoute = '/api/withSentryAPI/wrapped/cjsExport';
const interceptedWrappedRequest = interceptTracingRequest(
{
contexts: {
trace: {
op: 'http.server',
status: 'ok',
tags: { 'http.status_code': '200' },
},
},
transaction: `GET ${wrappedRoute}`,
type: 'transaction',
request: {
url: `${urlBase}${wrappedRoute}`,
},
},
argv,
'wrapped CJS route',
);
const responseWrapped = await getAsync(`${urlBase}${wrappedRoute}`);
assert.equal(responseWrapped, '{"success":true}');

await sleep(250);

assert.ok(interceptedUnwrappedRequest.isDone(), 'Did not intercept unwrapped request');
assert.ok(interceptedWrappedRequest.isDone(), 'Did not intercept wrapped request');
};

0 comments on commit b7c0e54

Please sign in to comment.