reador23
reador23β€’16mo ago

Express + tRPC: handle express errors from client

I currently have Express as backend and react on frontend. I want to migrate gradually to tRPC + react query. In order to do that I want to use the tRPC express middleware. I have tons of express middleware that I want to continue using for now, as well as error handlers. The problem is that the tRPC client (trpc react query) does not recognize express errors like custom session timeout, 401, etc, which is normal, so I get the "Unable to transform response from server". But I would like to know if there is an easy way to format express errors easily to tRPC errors, or if its possible to catch the error before tRPC client tries to transform it, so that I can handle it myself.
11 Replies
Alex / KATT 🐱
Alex / KATT πŸ±β€’16mo ago
You could potentially do a custom link that reformats error I think you have access to the response object there
reador23
reador23β€’16mo ago
Thats a good idea, I already have a custom link but when I log the error from there its already the tRPC error "Unable to transform response from server". Maybe I'm not doing it right, do you have an example of implementation ?
Alex / KATT 🐱
Alex / KATT πŸ±β€’16mo ago
working on it
Alex / KATT 🐱
Alex / KATT πŸ±β€’16mo ago
had to add support for it https://github.com/trpc/trpc/pull/4597
GitHub
feat(client): add HTTP response object to TRPCClientError meta ...
🎯 Changes Allows you to access: error.meta?.response error.meta?.responseJSON In for instance links etc
Alex / KATT 🐱
Alex / KATT πŸ±β€’16mo ago
released to 10.34.0 now you should be able to do custom stuff with that based on err.meta.responseJSON
reador23
reador23β€’16mo ago
Wow! Incredible support! Thank you so much, I will give it a try
Alex / KATT 🐱
Alex / KATT πŸ±β€’16mo ago
Feel free to get your employer to sponsor πŸ˜„
reador23
reador23β€’16mo ago
Ah I wish…, but my company in japan would probably laugh to my face for asking this. For now I’m trying to sell the idea of tRPC to my managers. So still working on a PoC. Maybe if one day tRPC becomes a huge part of my company tech stack Your fix indeed works as expected, I’m still having trouble on how to do error handling depending on this response, but I think it’s because I’m new to this concept of link and how it works, like how to throw a new error.
Alex / KATT 🐱
Alex / KATT πŸ±β€’16mo ago
you can probably do something like this to add extra metadata to it:
class MyCustomError extends TRPCClientError<AppRouter> {
constructor(message: string) {
super(message);
}
}

function isObject(value: unknown): value is Record<string, unknown> {
// check that value is object
return !!value && !Array.isArray(value) && typeof value === 'object';
}

const customErrorLink: TRPCLink<AppRouter> = (runtime) => (opts) =>
observable((observer) => {
const unsubscribe = opts.next(opts.op).subscribe({
error(err) {
if (
err.meta &&
isObject(err.meta.responseJSON) &&
'__error' in err.meta.responseJSON
) {
// custom error handling
observer.error(
new MyCustomError(
`custom error: ${JSON.stringify(
err.meta.responseJSON.__error,
)}`,
),
);
}
observer.error(err);
},
});
return unsubscribe;
});
class MyCustomError extends TRPCClientError<AppRouter> {
constructor(message: string) {
super(message);
}
}

function isObject(value: unknown): value is Record<string, unknown> {
// check that value is object
return !!value && !Array.isArray(value) && typeof value === 'object';
}

const customErrorLink: TRPCLink<AppRouter> = (runtime) => (opts) =>
observable((observer) => {
const unsubscribe = opts.next(opts.op).subscribe({
error(err) {
if (
err.meta &&
isObject(err.meta.responseJSON) &&
'__error' in err.meta.responseJSON
) {
// custom error handling
observer.error(
new MyCustomError(
`custom error: ${JSON.stringify(
err.meta.responseJSON.__error,
)}`,
),
);
}
observer.error(err);
},
});
return unsubscribe;
});
reador23
reador23β€’16mo ago
Oh thanks! I actually did something kind of similar, I will show you on Monday when I get back to work. It would be nice if it can help people in the future. I think its really important for people that want to migrate their big applications to tRPC as they want to be able to keep using their current code (in our case here its the error handling) and have time to gradually migrate. Maybe if I successfully do it, I could write an article or something on how I migrated a big production Express + SSR React app to tRPC.