Custom error management

Hey peeps! I could've sworn I created a GitHub issue about this, but I must've been dreaming, because I cannot find it. Anyway, it's support-related, so I figured it's better to ask here! I have a large application that has a traditional client/server API and I use Axios to make calls to the server. Now, I'm investigating replacing that with tRPC (because it feels like an amazing developer experience and will quicken development). I have a rather "sophisticated" error management in the application. I have my own custom ApplicationError, which has an errorCode and a custom data object with additional information about the error. Any server-side code in the application can throw this error. A middleware catches this and converts it to a 400 Bad Request with an appropriate JSON response body. In the client, I also have my custom wrapper on top of Axios, that simply catches 400 Bad Request, and converts the JSON back to an ApplicationError and simply throws it. This means that I can easily catch ApplicationError in my client side code, just as if it was originally thrown on the client. Now, I want to do something similar with tRPC. I see that we have the TRPCError, but I would love to be able to utilize my ApplicationError. For two reasons: 1. I don't want to re-write all my code. 2. I think it's a nice abstract layer that the majority of my server side code do not need to be aware of "tRPC". Does anyone have any ideas on how I can achieve this? I would need some kind of middleware on top of the tRPC procedure that catches my error and converts it into a TRPCError. I would also need some kind of filter in my tRPC client code that automatically converts this back into an ApplicationError and throws it. Any help or suggestions are appreciated! Thanks in advance.
N
Nickβ€’408d ago
errorFormatter and middlewares should do the trick You can remove a lot of your boilerplate because you’ve essentially described how tRPC handles errors too, albeit you probably won’t get back an instanceof your custom error class, just can add your extra data no problem An error catching middleware like before should be possible
A
anton.johanssonβ€’392d ago
Allright, I'll look into it, thanks Nick!
E
ensomniumβ€’390d ago
Did you figure this out @anton-johansson ? I'm using sveltekit and in order to redirect we need to throw unwrapped errors. @Nick Lucas any ideas how to get an unwrapped error out?
A
anton.johanssonβ€’381d ago
Hmm, I'm still struggling a little bit with this. Is there no way to convert it back to my own custom error on the client side, in a "generic" way? It feels like it should be relatively easy to hook in where the error object is being created, and convert it back to my own error type. @Nick Lucas Any ideas? Digging deep into the tRPC code at the moment, and it looks like the error must be of type TRPCClientError<MyRouter>. Otherwise, I could probably write my own httpBatchLink with custom error logic, but it looks like I can't.
N
Nickβ€’381d ago
I believe you could set up your transformer to achieve this Superjson can have custom types registered But it would be simpler to include a type key on the change so you can check the type of the error on the frontend
A
anton.johanssonβ€’380d ago
Well, I mostly want this because I feel it's clearer to handle my own error than a library-specific error. πŸ™‚ But it probably does not matter much. Anyway, I tried messing around with transformer, but it looks like the entire framework is tightly coupled with the TRPCClientError type. The TRPCLink type "forces" TRPCClientError. I'll see if I can easily work with TRPCClientError instead.
N
Nickβ€’380d ago
All our errors I believe have cause keys, your error will be contained within and you can access it in the error formatter
A
anton.johanssonβ€’380d ago
Yeah, but I'd love to be able to do something like this:
const myAction = trpc.myAction.useMutation();
const onClick = async () => {
try {
await myAction.mutateAsync();
} catch (error: unknown) {
if (error instanceof ApplicationError) {
// handle my own error type
} else {
// show some generic error
}
}
};
const myAction = trpc.myAction.useMutation();
const onClick = async () => {
try {
await myAction.mutateAsync();
} catch (error: unknown) {
if (error instanceof ApplicationError) {
// handle my own error type
} else {
// show some generic error
}
}
};
But I think this won't work, I'll have to work with the TRPCClientError.
N
Nickβ€’380d ago
Feel free to open a github issue, and PRs are welcome πŸ™‚
A
anton.johanssonβ€’380d ago
I had some thoughts first, but I think I can make it very similar with the TRPCClientError, I'm gonna mess around a bit with it. πŸ™‚ I just like the idea of having the same error on the server and on the client, but it's more a personal thing.
N
Nickβ€’380d ago
I suspect the benefit isn't that clear though, using the error formatter to output an object with a type string you can switch on will produce the same effect, and serialising errors even with a transformer is likely to be a nightmare
A
anton.johanssonβ€’380d ago
Yeah I get it, I just figured that you could allow "converting" a TRPCClientError into my own error before throwing it, but I'm not sure if it's worth the effort.
N
Nickβ€’380d ago
TRPCClientError does have a cause key by the way, worth checking if that already contains what you want
A
anton.johanssonβ€’380d ago
Yeah I'll check! Looks like the cause is undefined here So I'd have to work with the data instead, which is most likely fine. πŸ™‚
More Posts
context questionWhy are the context examples only showing opinionated examples with next/react auth ? Also i find itasync middlewareis it possible to define an async middleware? I want to do something like this but it throws errors The type of the second route of the nested route is neverhttps://github.com/StringKe/nx-mulit-trpc-type-error/blob/main/apps/app1/src/pages/index.tsx#L12errorFormatter ignored when using appRouter.createCallerMy errorFormatter works correctly in the actual application using an adapter, e.g. ``` trpcExpress.Is there a way to define the Websocket protocol when using wsLink()I am attempting to use tRPC with Azure's Pub/Sub Websockets service it appears to require custom proThe inferred type of this node exceeds the maximum length the compiler will serialize.Hey, there I am running into this error when I have more than 12 routers in the mergeRouters functioQuickstart not workingHello there, There is a type error in the quickstart example if i'm not mistaken. I pretty much coUse TRPC function inside of a TRPC functionHi all! We have a trpc query called getProduct. I want to use this getProduct query inside of anotheSupabase with trpcWhen trying to configure trpc with supabase, getting this kind of error in the console `tRPC failed Using tRPC for uploading audio filesI want to create an api router in tRPC but am not sure if the following code is doable with tRPC. IfEnigmatic INTERNAL SERVER ERRORIm having a problem finding out about what is causing the INTERNAL SERVER ERROR from tRPC in my prodcreateProxySSGHelpers type errorHi all! Anyone know how to use createProxySSGHelpers with appropriate createContext typing?Can I force metadata with the createCaller?I have custom metadata which I check within the middleware. Im trying to write tests for this. CurreVitest error testHow can I test for specific TRPCError code with vitest? I managed to get the message but can't figurUsing generics duplicates the types instead of referring to the existing typesHi! I'm creating a backend API using TRPC, where I'm encountering a slight problem. TL;DR; when defSet custom header for fetchRequestHandlerIs this possible? currently getting cors issue. Trying to use nextjs's edge function with trpc.. ``How to enforce usequery as NonNullableI have a custom hook with infinite query. I check for undefined at the app first render and then it How to call useQuery with params inside JSXHow can i achieve this? Thanks ``` export function MemberQueryList({ list }: Props) { function Sharing EnumOn the backend: I have colocated files with types and procedures (index.ts - procedures, schemas.ts Meta - unable to create default metaTrying to follow https://trpc.io/docs/server/metadata#default-meta-chaining-and-shallow-merging I se