網站搜尋

typescript - tRPC 如何封裝中介軟體?


我正在嘗試把中介軟體放到它自己的函數中,但我在給它正確的 TypeScript 類型時遇到了困難。

目前我正在如下編寫中介軟體,但這並不理想,因為從中介軟體返回後,context 和 metadata 的類型資訊會丟失。

在中介軟體內

import { MiddlewareFunction } from "@trpc/server/dist/declarations/src/internals/middlewares";
import { TRPCError } from "@trpc/server";


export const authMiddleware : MiddlewareFunction<any, any, any> = async ({ ctx, next, path, rawInput, type, meta }) => {
  if (!meta?.auth)
    return next();

  // some random logic

  return next();
}

這就是我想要消費它的方式

createRouter()
  .middleware(authMiddleware)
  .mutation('', {
    meta: {
      auth: "user",
      appCheck: true
    },
    input: object({
      workshopId: idSchema,
    }),
    resolve: async ({ input, ctx, type }) => {
    // Here ctx has been widened to any
    // ...

提前感謝你。

答案#1

const t = initTRPC.context<Context>().create();
const middleware = t.middleware;

const authMiddleware = t.middleware(({ next, ctx }) => {
  if (!ctx.session) {
    throw new TRPCError({
      code: "UNAUTHORIZED",
    });
  }
  return next({
    ctx: {
      // Infers the `session` as non-nullable
      session: ctx.session,
    },
  });
})

答案#2

我遇到了同樣的問題(trpc v9.27),所以我直接從 trpc 路由器上的中介軟體方法取得了類型。

import * as trpc from "@trpc/server"

// context for router
const createContext = async () => ({hi: "hi"})

type Context = trpc.inferAsyncReturnType<typeof createContext>

// router initialization function
const trpcRouter = () => trpc.router<Context>()

const router = trpcRouter()
// don't forget to add the return type for your middleware
// in the generic
const init = router.middleware<Context>
type MiddlewareFunction = Parameters<typeof init>[0]

// now use for your middlewares
const myMiddleware: MiddlewareFunction = ({next, ctx}) => {
    console.log("my context", ctx)
    next()
}

// go nuts and use it where you want
export const myCoolRoutes = router
    .middleware(myMiddleware)
    .query("coolio", ({ctx}) => true)

請注意,如果你打算在你的某個中介軟體函數中更改上下文,router.middleware 泛型應該要反映這一點。例如,如果你想在中介軟體中向上下文添加鍵,你需要定義一個新的上下文類型,來添加你想要的鍵:

// add your keys to context
type keys = {newKey: number}
const mutatingMiddleware = router.middleware<Context & keys>
type Mutate = Parameters<typeof mutatingMiddleware>[0]

const mutatator: Mutate = ({ctx, next}) => {
    return next({ctx: {...ctx, newKey: 0}})
}

希望這對你有幫助。