Home > Enterprise >  How to properly use context in tRPC?
How to properly use context in tRPC?

Time:09-14

Let's say I have a very basic API with two sets of endpoints. One set queries and mutates properties about a User, which requires a username parameter, and one set queries and mutates properties about a Post, which requires a post ID. (Let's ignore authentication for simplicity.) I don't currently see a good way to implement this in a DRY way.

What makes the most sense to me is to have a separate Context for each set of routes, like this:

// post.ts
export async function createContext(
    opts?: trpcExpress.CreateExpressContextOptions
) {
    // pass through post id, throw if not present
}
type Context = trpc.inferAsyncReturnType<typeof createContext>;

const router = trpc
    .router()
    .query("get", {
        resolve(req) {
            // get post from database
            return post;
        },
    });

// similar thing in user.ts

// server.ts
const trpcRouter = trpc
    .router()
    .merge("post.", postRouter)
    .merge("user.", userRouter);

app.use(
    "/trpc",
    trpcExpress.createExpressMiddleware({
        router: trpcRouter,
        createContext,
    })
);

This complains about context, and I can't find anything in the tRPC docs about passing a separate context to each router when merging. Middleware doesn't seem to solve the problem either - while I can fetch the post/user in a middleware and pass it on, I don't see any way to require a certain type of input in a middleware. I would have to throw { input: z.string() } or { input: z.number() } on every query/mutation, which of course isn't ideal.

The docs and examples seem pretty lacking for this (presumably common) use case, so what's the best way forward here?

CodePudding user response:

This functionality has been added in (unreleased as of writing) v10. https://trpc.io/docs/v10/procedures#multiple-input-parsers

const roomProcedure = t.procedure.input(
  z.object({
    roomId: z.string(),
  }),
);
 
const appRouter = t.router({
  sendMessage: roomProcedure
    .input(
      z.object({
        text: z.string(),
      }),
    )
    .mutation(({ input }) => {
      // input: { roomId: string; text: string }
    }),
});
  • Related