How to perform additional validation on update mutation?

I want to protect each user's data so it can't be modified if you aren't the user who created the object (userId as foreign key). Here is my work in progress update mutation. I want to ensure that the object.userId matches the ctx.auth.userId before allowing to update it.
update: protectedProcedure
.input(
z.object({
id: z.string(),
name: z.string(),
description: z.string(),
value: z.number(),
userId: z.string(),
}))
.mutation(({ctx, input}) => {
return ctx.prisma.transaction.update({
where: { id: input.id },
data: { ...input, userId: ctx.auth.userId }
})
})
update: protectedProcedure
.input(
z.object({
id: z.string(),
name: z.string(),
description: z.string(),
value: z.number(),
userId: z.string(),
}))
.mutation(({ctx, input}) => {
return ctx.prisma.transaction.update({
where: { id: input.id },
data: { ...input, userId: ctx.auth.userId }
})
})
Since the above where only accepts id prop, I think I can add a find query before it and verify the userId matches ctx.prisma.transaction.update call
const found = ctx.prisma.transaction.findFirst({where: {id: input.id, userId: input.userId}});
if(!found) { throw new TRPCError({code:'UNAUTHORIZED"}); }
const found = ctx.prisma.transaction.findFirst({where: {id: input.id, userId: input.userId}});
if(!found) { throw new TRPCError({code:'UNAUTHORIZED"}); }
Does this make sense? Although from a db standpoint, these count as two separate db calls right?
2 Replies
Tom
Tom2y ago
why not just not accept userId as an input and use the value straight from ctx.auth.userId? then you could also in your where clause add userId: ctx.auth.userId. That way itll only update if the userId matches (i dont use prisma in my project, but thats how i would do it with any db driver) as for your find query, I dont think you need it, but yes that would count as a separate db roundtrip (also you would need to await the response)
Mendy
Mendy2y ago
I agree with @Tom3 I’ll add that you can await the update query, check if an update was done, and then throw an authorization error if it was not. Otherwise, return the updated object.
Want results from more Discord servers?
Add your server