thibault
thibault
TtRPC
Created by thibault on 10/10/2024 in #❓-help
Basic error handling patterns
Hello guys I am playing around with trpc and I don't know how to do error handling at a route level. I did read the docs about error handling but I don't know if my approach to this problem is good. How do you guys would handle errors in trpc ? For example I have this sign up route. And the way I am doing error handling is by re throwing a TRPCError in the catch clause. Which doesn't seems right.
signUp: publicProcedure
.input(signUpSchema)
.mutation(async ({ ctx, input }) => {
try {
// ...

// could throw on duplicate email.
await ctx.db.insert(userTable).values(...);

// ...
} catch (e) {
if (isPgError(e) && e.constraint_name === "user_email_unique") {
throw new TRPCError({
code: "CONFLICT",
message: "this email is already used",
});
}

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: e instanceof Error ? e.message : "unhandled error",
});
}
}),
signUp: publicProcedure
.input(signUpSchema)
.mutation(async ({ ctx, input }) => {
try {
// ...

// could throw on duplicate email.
await ctx.db.insert(userTable).values(...);

// ...
} catch (e) {
if (isPgError(e) && e.constraint_name === "user_email_unique") {
throw new TRPCError({
code: "CONFLICT",
message: "this email is already used",
});
}

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: e instanceof Error ? e.message : "unhandled error",
});
}
}),
I also try to use the middleware approach but that doesn't work since trpc override the error constructor.
signUp: publicProcedure
.input(signUpSchema)
.use(async ({ctx, next})=>{
const res = await next();

// does not work since the instance of res.error is no longer PostgresError but TRPCError
if(!res.ok && isPgError(res.error) && res.error.constraint_name === "user_email_unique") {
throw new TRPCError({
code: "CONFLICT",
message: "this email is already used",
});
}

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: res.error instanceof Error ? res.error.message : "unhandled error",
});
})
.mutation(async ({ ctx, input }) => {
// ...

// could throw on duplicate email.
await ctx.db.insert(userTable).values(...);

// ...
}),
signUp: publicProcedure
.input(signUpSchema)
.use(async ({ctx, next})=>{
const res = await next();

// does not work since the instance of res.error is no longer PostgresError but TRPCError
if(!res.ok && isPgError(res.error) && res.error.constraint_name === "user_email_unique") {
throw new TRPCError({
code: "CONFLICT",
message: "this email is already used",
});
}

throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: res.error instanceof Error ? res.error.message : "unhandled error",
});
})
.mutation(async ({ ctx, input }) => {
// ...

// could throw on duplicate email.
await ctx.db.insert(userTable).values(...);

// ...
}),
2 replies