T
T16mo ago

tRPC middleware infer type from another protectedProcedure

Hello, protectedProcedure check and adds a not nullable user to the ctx. However the studyMiddleware does not know that user is not nullable, is there a way for the middleware to be aware of it? In my current code I had to validate the user is not nullable inside the middleware and had to manually pass the user to the ctx user: opts.ctx.user, to make user not nullable inside the mutation. Here is a sample of my code
const studyMiddleware = middleware(async (opts) => {
if (!opts.ctx.user) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "Unauthorized",
});
}

const parsedInput = z
.object({
studyId: z.string().cuid(),
})
.parse(opts.input);

const study = await studyRepository.findOneByIdAndClientId({
id: parsedInput.studyId,
clientId: opts.ctx.user.client.id,
});

if (!study) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Study not found",
});
}

return opts.next({
ctx: {
...opts.ctx,
user: opts.ctx.user,
study,
},
});
});

export const budgetRouter = createTRPCRouter({
create: protectedProcedure
.use(studyMiddleware)
.input(createBudgetInputSchema)
.mutation(({ input, ctx: { user, study } }) =>
budgetService.create(input, user, study),
),
});
const studyMiddleware = middleware(async (opts) => {
if (!opts.ctx.user) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "Unauthorized",
});
}

const parsedInput = z
.object({
studyId: z.string().cuid(),
})
.parse(opts.input);

const study = await studyRepository.findOneByIdAndClientId({
id: parsedInput.studyId,
clientId: opts.ctx.user.client.id,
});

if (!study) {
throw new TRPCError({
code: "NOT_FOUND",
message: "Study not found",
});
}

return opts.next({
ctx: {
...opts.ctx,
user: opts.ctx.user,
study,
},
});
});

export const budgetRouter = createTRPCRouter({
create: protectedProcedure
.use(studyMiddleware)
.input(createBudgetInputSchema)
.mutation(({ input, ctx: { user, study } }) =>
budgetService.create(input, user, study),
),
});
1 Reply
seN49
seN4915mo ago
I've found using procedure works better for types than the middleware. If you change your middleware and use .use it should probably work as you expect!

Did you find this page helpful?