Mattèo
Mattèo•11mo ago

How to handle Query Errors on client side (show toast on 401)

Hey ! Hope you're doing well ! I wanted to know if someone can explain to me how to handle errors on the client (using Next.js). I need to handle UNAUTHENTICATED error on client because when a user tries to access a resource I want to display a feedback toast. Thanks 🙏
1 Reply
Twan
Twan•11mo ago
Hey, I have had the same issue and what you looking for is creating a link https://trpc.io/docs/client/links#creating-a-custom-link.
export const customLink: TRPCLink<AppRouter> = () => {
// here we just got initialized in the app - this happens once per app
// useful for storing cache for instance
return ({ next, op }) => {
// this is when passing the result to the next link
// each link needs to return an observable which propagates results
return observable(observer => {
const unsubscribe = next(op).subscribe({
next(value) {
// @ts-ignore TODO: fix the typing on these 2 values
if (value.context?.response?.status === 401) {
core.logged_in.set(false);

core.account.set(null);
core.tickets.reset();
core.account.reset();
core.linkingArgs.reset();
core.notifications.reset();
}
},
error(err) {
// @ts-ignore
if (err?.meta?.response?.status === 401) {
core.logged_in.set(false);

core.account.set(null);
core.tickets.reset();
core.account.reset();
core.linkingArgs.reset();
core.notifications.reset();
}

observer.error(err);
},
complete() {
observer.complete();
},
});
return unsubscribe;
});
};
};

export const client = createTRPCProxyClient<AppRouter>({
links: [
customLink,
httpBatchLink({
url: `${core.API_HOST._value}/trpc`,
// You can pass any HTTP headers you wish here
fetch(url: any, options: any) {
return fetch(url, {
...options,
credentials: 'include',
});
},
}),
],
});
export const customLink: TRPCLink<AppRouter> = () => {
// here we just got initialized in the app - this happens once per app
// useful for storing cache for instance
return ({ next, op }) => {
// this is when passing the result to the next link
// each link needs to return an observable which propagates results
return observable(observer => {
const unsubscribe = next(op).subscribe({
next(value) {
// @ts-ignore TODO: fix the typing on these 2 values
if (value.context?.response?.status === 401) {
core.logged_in.set(false);

core.account.set(null);
core.tickets.reset();
core.account.reset();
core.linkingArgs.reset();
core.notifications.reset();
}
},
error(err) {
// @ts-ignore
if (err?.meta?.response?.status === 401) {
core.logged_in.set(false);

core.account.set(null);
core.tickets.reset();
core.account.reset();
core.linkingArgs.reset();
core.notifications.reset();
}

observer.error(err);
},
complete() {
observer.complete();
},
});
return unsubscribe;
});
};
};

export const client = createTRPCProxyClient<AppRouter>({
links: [
customLink,
httpBatchLink({
url: `${core.API_HOST._value}/trpc`,
// You can pass any HTTP headers you wish here
fetch(url: any, options: any) {
return fetch(url, {
...options,
credentials: 'include',
});
},
}),
],
});
Links Overview | tRPC
Links enable you to customize the flow of data between the tRPC Client and Server. A link should do only one thing, which can be either a self-contained modification to a tRPC operation (query, mutation, or subscription) or a side-effect based on the operation (such as logging).