function
function
TtRPC
Created by function on 1/30/2025 in #❓-help
Throw NOT_FOUND on nullish
I have many procedures like this: getFoo: protectedProcedure.query(({ input }) => db.foo.findFirst({ id: input.id }) This example uses Drizzle, which doesn't have a findFirstOrThrow convenience function. Since i want to throw TRPCError when the DB record couldn't be found, i'd have to write this code everywhere:
getFoo: protectedProcedure.query(async ({ input }) => {
const maybeFoo = await db.foo.findFirst({ id: input.id })
if (maybeFoo === undefined) {
throw new TRPCError({ code: "NOT_FOUND" })
}
return maybeFoo
})
getFoo: protectedProcedure.query(async ({ input }) => {
const maybeFoo = await db.foo.findFirst({ id: input.id })
if (maybeFoo === undefined) {
throw new TRPCError({ code: "NOT_FOUND" })
}
return maybeFoo
})
Is there a nicer way to achieve this when dealing with nullish return values? My research so far: - Output validators are not a solution because when they fail it results in a INTERNAL_SERVER_ERROR. - Middleware sounds like it should be the natural solution but the documentation doesn't show any examples accessing procedure data, i.e. post-procedure middleware. There is a discussion on accessing req/res but the solution instructing to use context sounds very hacky and will definitely not get me type-safe results. - There's also a Drizzle issue to add findFirstOrThrow from 2023 but it doesn't look like they'll implement this anytime soon. - This actually works and is type-safe (removes nullish from resulting type) but kind of ugly in usage:
export const throwOnNullish = <T>(promise: Promise<T>) =>
promise.then((anything) => {
if (anything === undefined || anything === null) {
throw new TRPCError({ code: "NOT_FOUND" });
}

return anything;
});
export const throwOnNullish = <T>(promise: Promise<T>) =>
promise.then((anything) => {
if (anything === undefined || anything === null) {
throw new TRPCError({ code: "NOT_FOUND" });
}

return anything;
});
2 replies
TtRPC
Created by function on 1/28/2025 in #❓-help
How can i check if an error is a TRPC Error in the browser?
error.message // NOT_FOUND (throwing this intentionally - i'd like to build a react error boundary that has specific handling for TRPC Errors like NOT_FOUND)
Object.getPrototypeOf(error) // default "Error" object/class
error instanceof TRPCClientError // false. this would have been my best bet.
error.message // NOT_FOUND (throwing this intentionally - i'd like to build a react error boundary that has specific handling for TRPC Errors like NOT_FOUND)
Object.getPrototypeOf(error) // default "Error" object/class
error instanceof TRPCClientError // false. this would have been my best bet.
3 replies
TtRPC
Created by function on 11/21/2024 in #❓-help
Is there a CMS that supports tRPC?
Title
2 replies
TtRPC
Created by function on 9/23/2024 in #❓-help
Why not create queryClient and trpcClient outside of React?
From the docs: https://trpc.io/docs/client/react/setup#4-add-trpc-providers Relevant excerpt:
export function App() {
const [queryClient] = useState(() => new QueryClient())
const [trpcClient] = useState(() =>
trpc.createClient({ /* ... */ }),
)

// ...
export function App() {
const [queryClient] = useState(() => new QueryClient())
const [trpcClient] = useState(() =>
trpc.createClient({ /* ... */ }),
)

// ...
What are the downsides to moving these two clients outside the component? Does it break hot reloading or something? E.g.
const queryClient = new QueryClient()
const trpcClient = trpc.createClient({ /* ... */ })

export function App() {
// ...
const queryClient = new QueryClient()
const trpcClient = trpc.createClient({ /* ... */ })

export function App() {
// ...
4 replies
TtRPC
Created by function on 6/21/2024 in #❓-help
Why are `new QueryClient` and `trpc.createClient` run inside a component in the React setup?
From https://trpc.io/docs/client/react/setup:
function App() {
const [queryClient] = useState(() => new QueryClient());
const [trpcClient] = useState(() =>
trpc.createClient({ ... }),
);
// ...
function App() {
const [queryClient] = useState(() => new QueryClient());
const [trpcClient] = useState(() =>
trpc.createClient({ ... }),
);
// ...
if these two are "made stable" through useState() and since they should exist only once per SPA (like a singleton), why not just put them outside the component? is this related to HMR?
25 replies
TtRPC
Created by function on 12/26/2023 in #❓-help
How can i use inferprocedureoutput?
I'd like to write this code type-safely:
const handleQuery = (query: /* ? */) => {}

const MyComponent = () => {
const query = trpc.foo.useQuery()
handleQuery(query)
// ...
}
const handleQuery = (query: /* ? */) => {}

const MyComponent = () => {
const query = trpc.foo.useQuery()
handleQuery(query)
// ...
}
I'm pretty sure i need to use inferProcedureOutput but i couldn't figure out what to pass. I can never access query.isLoading for example.
4 replies
TtRPC
Created by function on 11/17/2023 in #❓-help
Globally handle specific Error type on backend
Hi, i have a lot of code that's used for both backend and frontend. That's why i'm not throwing TRPCErrors but custom errors instead. They indicate that the error message should be sent to the client if it arises on the backend (on the frontend this obviously doesn't matter). Can i set up the tRPC server side in a way where it will catch all errors so i can do something like this?
if (error instanceof DispatchableError) {
throw new TRPCError({
code: "BAD_REQUEST",
message: error.message,
});
} else {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Sorry, something went wrong"
})
}
if (error instanceof DispatchableError) {
throw new TRPCError({
code: "BAD_REQUEST",
message: error.message,
});
} else {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Sorry, something went wrong"
})
}
7 replies
TtRPC
Created by function on 9/12/2023 in #❓-help
404 TRPCError: no query procedure on path
Hi, this is my entire standalone tRPC server:
import { initTRPC } from "@trpc/server";
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import cors from "cors";

const t = initTRPC.create();
const appRouter = t.router({
foo: t.procedure.query(() => "hi"),
});

const server = createHTTPServer({
middleware: cors(),
router: appRouter,
});

export type AppRouter = typeof appRouter;

server.listen(3000);
import { initTRPC } from "@trpc/server";
import { createHTTPServer } from "@trpc/server/adapters/standalone";
import cors from "cors";

const t = initTRPC.create();
const appRouter = t.router({
foo: t.procedure.query(() => "hi"),
});

const server = createHTTPServer({
middleware: cors(),
router: appRouter,
});

export type AppRouter = typeof appRouter;

server.listen(3000);
and here is my tRPC client:
const trpcClient = trpc.createClient({
links: [
httpBatchLink({
url: "http://localhost:3000/trpc"
}),
],
});
const trpcClient = trpc.createClient({
links: [
httpBatchLink({
url: "http://localhost:3000/trpc"
}),
],
});
but when i use it with trpc.foo.useQuery(), this the response:
{
"error": {
"message": "No \"query\"-procedure on path \"trpc/foo\"",
"code": -32004,
"data": {
"code": "NOT_FOUND",
"httpStatus": 404,
"stack": "TRPCError: No \"query\"-procedure on path \"trpc/foo\"\n at new TRPCError (/somepath/node_modules/@trpc/server/dist/TRPCError-6a1653a4.mjs:52:12)\n at callProcedure
[...]
}
}
}
{
"error": {
"message": "No \"query\"-procedure on path \"trpc/foo\"",
"code": -32004,
"data": {
"code": "NOT_FOUND",
"httpStatus": 404,
"stack": "TRPCError: No \"query\"-procedure on path \"trpc/foo\"\n at new TRPCError (/somepath/node_modules/@trpc/server/dist/TRPCError-6a1653a4.mjs:52:12)\n at callProcedure
[...]
}
}
}
What am i doing wrong? I already tried removing /trpc from the url that the client uses which also resulted in 404.
18 replies
TtRPC
Created by function on 5/14/2023 in #❓-help
Why does this starter with Prisma have it's own postinstall script?
4 replies
TtRPC
Created by function on 4/28/2023 in #❓-help
next-prisma-websockets-starter seeds twice on 'pnpm dx'
Hi, i'm using this starter template for my app. The dx script from package.json runs both prisma migrate as well as prisma seed and the former seems to run the seeder as well, causing data to exist twice in the database after running dx. Link to line in package.json: https://github.com/trpc/examples-next-prisma-websockets-starter/blob/db3a7794caa8d024f7115ce1f767d84c0172dd93/package.json#L21
2 replies