import type { NextApiRequest, NextApiResponse } from "next"; import { TRPCError } from "@trpc/server"; import { getHTTPStatusCodeFromError } from "@trpc/server/http"; import { HttpError } from "../http-error"; import { getServerErrorFromUnknown } from "./getServerErrorFromUnknown"; import { performance } from "./perfObserver"; type Handle = (req: NextApiRequest, res: NextApiResponse) => Promise; /** Allows us to get type inference from API handler responses */ export function defaultResponder( f: Handle, /** If set we will wrap the handle with sentry tracing */ endpointRoute?: string ) { return async (req: NextApiRequest, res: NextApiResponse) => { let ok = false; try { performance.mark("Start"); let result: T | undefined; if (process.env.NODE_ENV === "development" || !endpointRoute) { result = await f(req, res); } else { const { wrapApiHandlerWithSentry } = await import("@sentry/nextjs"); result = await wrapApiHandlerWithSentry(f, endpointRoute)(req, res); } ok = true; if (result && !res.writableEnded) { return res.json(result); } } catch (err) { let error: HttpError; if (err instanceof TRPCError) { const statusCode = getHTTPStatusCodeFromError(err); error = new HttpError({ statusCode, message: err.message }); } else { error = getServerErrorFromUnknown(err); } // we don't want to report Bad Request errors to Sentry / console if (!(error.statusCode >= 400 && error.statusCode < 500)) { console.error(error); const { captureException } = await import("@sentry/nextjs"); captureException(error); } return res .status(error.statusCode) .json({ message: error.message, url: error.url, method: error.method, data: error?.data || null }); } finally { performance.mark("End"); performance.measure(`[${ok ? "OK" : "ERROR"}][$1] ${req.method} '${req.url}'`, "Start", "End"); } }; }