Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions apps/web/src/app/api/trpc/[trpc]/route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { afterEach, expect, it, jest } from '@jest/globals';
import { initTRPC, TRPCError } from '@trpc/server';

jest.mock('@/lib/trpc/init', () => ({
createTRPCContext: () => ({}),
}));

jest.mock('@/routers/root-router', () => {
const t = initTRPC.create();
return {
rootRouter: t.router({
ok: t.procedure.query(() => 'ok'),
fail: t.procedure.query(() => {
throw new TRPCError({
code: 'BAD_REQUEST',
message: 'SYNTHETIC_SENSITIVE_TOKEN',
});
}),
}),
};
});

afterEach(() => {
jest.restoreAllMocks();
});

it.each(['development', 'production', 'test'] as const)(
'logs only safe batch error fields in development, with NODE_ENV=%s',
async nodeEnv => {
jest.replaceProperty(process, 'env', { ...process.env, NODE_ENV: nodeEnv });
const log = jest.spyOn(console, 'error').mockImplementation(() => {});
const { GET } = await import('./route');

const response = await GET(new Request('http://localhost/api/trpc/ok,fail?batch=1'));

expect(response.status).toBe(207);
if (nodeEnv === 'development') {
expect(log.mock.calls).toEqual([['[trpc] query fail failed: BAD_REQUEST']]);
} else {
expect(log).not.toHaveBeenCalled();
}
}
);
10 changes: 10 additions & 0 deletions apps/web/src/app/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,16 @@ const handler = (req: Request) =>
router: rootRouter,
createContext: createTRPCContext,
allowMethodOverride: true,
// A batched call answers 207 when one procedure fails, and folds the failure
// into the response body. Without this the server log shows only the 207, so
// nobody can tell which of a dozen batched procedures raised, or why.
// Development only: production reporting is unchanged.
onError:
process.env.NODE_ENV === 'development'
? ({ path, type, error }) => {
console.error(`[trpc] ${type} ${path ?? '<no path>'} failed: ${error.code}`);
}
: undefined,
});

export { handler as GET, handler as POST };