|
| 1 | +// We import these types from `withSentry` rather than directly from `next` because our version can work simultaneously |
| 2 | +// with multiple versions of next. See note in `withSentry` for more. |
| 3 | +import type { NextApiHandler, WrappedNextApiHandler } from '../../utils/withSentry'; |
| 4 | +import { withSentry } from '../../utils/withSentry'; |
| 5 | + |
| 6 | +/** |
| 7 | + * Wrap the given API route handler for tracing and error capturing. Thin wrapper around `withSentry`, which only |
| 8 | + * applies it if it hasn't already been applied. |
| 9 | + * |
| 10 | + * @param maybeWrappedHandler The handler exported from the user's API page route file, which may or may not already be |
| 11 | + * wrapped with `withSentry` |
| 12 | + * @param parameterizedRoute The page's route, passed in via the proxy loader |
| 13 | + * @returns |
| 14 | + */ |
| 15 | +export function withSentryAPI( |
| 16 | + maybeWrappedHandler: NextApiHandler | WrappedNextApiHandler, |
| 17 | + parameterizedRoute: string, |
| 18 | +): WrappedNextApiHandler { |
| 19 | + // We want the innards of `withSentry` to have access to the parameterized route, so it can be used when we start the |
| 20 | + // request transaction. If we were always the ones calling `withSentry` (the way we're always the ones to call |
| 21 | + // `withSentryServerSideProps`, for example), then we could just pass it in as a second parameter and know it would |
| 22 | + // always be there. But in the case where users have already manually wrapped their API route handlers with |
| 23 | + // `withSentry`, they're the ones calling it, without the parameterized route as a second parameter. We therefore need |
| 24 | + // a different way to make it available, which we'll do by storing it on the handler or handler wrapper, depending on |
| 25 | + // what we're given. |
| 26 | + maybeWrappedHandler.__sentry_route__ = parameterizedRoute; |
| 27 | + |
| 28 | + // In the simple case, where the handler has not yet been wrapped, `maybeWrappedHandler` will be passed to |
| 29 | + // `withSentry` as `origHandler` and so the parameterized route will be easy to access. |
| 30 | + if (!('__sentry_wrapped__' in maybeWrappedHandler)) { |
| 31 | + return withSentry(maybeWrappedHandler); |
| 32 | + } |
| 33 | + |
| 34 | + // In the case where the exported handler is already of the form `withSentry(origHandler)`, `maybeWrappedHandler` is |
| 35 | + // the wrapped handler returned by `withSentry`, which now has the parameterized route as a property on itself. By |
| 36 | + // default in JS, functions have `global` as their `this` value, so to be able to get at the route value, we need to |
| 37 | + // make sure it's called with itself as `this`. Since ultimately we need to give nextjs something *it* will call (and |
| 38 | + // it won't set the `this` value we want when it does), this means one more wrapper. |
| 39 | + const newWrapper: WrappedNextApiHandler = (req, res) => { |
| 40 | + // Make `maybeyWrappedHandler` its own `this` |
| 41 | + return maybeWrappedHandler.call(maybeWrappedHandler, req, res); |
| 42 | + }; |
| 43 | + |
| 44 | + return newWrapper; |
| 45 | +} |
0 commit comments