Skip to content

tRPC guide (@trpc/server) #2286

Open
Open
@xferqr

Description

Docs: https://trpc.io/

Server.ts:

export class Server {
  @Inject()
  protected app: PlatformApplication
.....
  @Inject()
  protected trpcService: tRPCservice
.....
}

/router/userRouter.ts:

import { z } from 'zod'
import { publicProcedure, t } from '../createRouterHelper'

import { LocalProtocol } from '../../protocols'
import { Inject, Injectable } from '@tsed/di'

@Injectable()
export class UserRouter {
  @Inject()
  private localAuthProtocol: LocalProtocol

  init() {
    return t.router({
      login: publicProcedure
        .input(
          z.object({
            login: z.string(),
            password: z.string().or(z.number())
          })
        )
        .mutation(async (req) => {
          return await this.localAuthProtocol.$onVerify(req.ctx.req, req.input)
        }),
    })
  }
}

createRouterHelper.ts:

import * as trpc from '@trpc/server'
import { TRPCError } from '@trpc/server'
import superjson from 'superjson'

import { Context } from './context'

export const t = trpc.initTRPC.context<Context>().create({
  transformer: superjson
})

export const trpcRouter = t.router
export const publicProcedure = t.procedure
export const middleware = t.middleware
export const mergeRouters = t.mergeRouters

export const isAuthMiddleware = middleware(async ({ ctx, next }) => {
  if (!ctx.user?.id) {
    throw new TRPCError({ code: 'UNAUTHORIZED' })
  }
  return next({
    ctx
  })
})

export const authProcedure = publicProcedure.use(isAuthMiddleware)

router.ts:

      import { UserRouter } from "./routes/userRouter";
      import { trpcRouter } from "./createRouterHelper";
      import { Inject, Injectable } from "@tsed/di";

      @Injectable()
      export class TRPCRouter {
        @Inject()
        private userRouter: UserRouter;

        createRouter() {
          return trpcRouter({
            user: this.userRouter.init(),
          });
        }
      }

      export type AppRouter = ReturnType<TRPCRouter["createRouter"]>;

context.ts:

    import { User } from "@prisma/client"
    import { Inject, Injectable, ProviderScope, Scope } from "@tsed/di"
    import { $prisma } from "../PrismaInstance"
    import * as jwt from 'jsonwebtoken'
    import * as trpcExpress from '@trpc/server/adapters/express'

    import { JwtProtocol } from "../protocols"
    import { inferAsyncReturnType } from "@trpc/server"

    @Injectable()
    @Scope(ProviderScope.SINGLETON)
    export class TRPCContext {
      @Inject()
      private jwtProtocol: JwtProtocol
      
      //DEMO verify jwt
      private verifyJwt(req: trpcExpress.CreateExpressContextOptions['req']) {
        let token = String(req.headers.authorization).split(' ')[1]
        return (token && jwt.verify(token, 'thisismysupersecretprivatekey1')) || undefined
      }

      async createContext({ req, res }: trpcExpress.CreateExpressContextOptions) {
        let user: User | undefined | null = undefined

        try { user = await this.jwtProtocol.$onVerify(req, this.verifyJwt(req))} catch (error) {}
        return { req, res, user, prisma: $prisma }
      }

    }

    export type Context = inferAsyncReturnType<TRPCContext['createContext']>

tRPCservice.ts:

    import { Injectable, Inject } from '@tsed/di'
    import { PlatformApplication, Req, Res } from '@tsed/common'

    import * as trpcExpress from '@trpc/server/adapters/express'
    import { TRPCRouter } from './router'
    import { TRPCContext } from './context'

    @Injectable()
    export class tRPCservice {
      @Inject()
      protected app: PlatformApplication<Express.Application>

      @Inject()
      trpcRouter: TRPCRouter

      @Inject()
      trpcContext: TRPCContext

      async $onInit() {
        const trpcApiEndpoint = '/trpc'

        const routes = this.trpcRouter.createRouter()
        const createContext = this.trpcContext.createContext.bind(this.trpcContext)

        this.app
          .use((req: Req, res: Res, next: () => void) => {
            res.setHeader('Access-Control-Allow-Origin', '*')
            res.setHeader('Access-Control-Request-Method', '*')
            res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET')
            res.setHeader('Access-Control-Allow-Headers', '*')
            // res.header("Access-Control-Allow-Credentials", "true")
            if (req.method === 'OPTIONS') {
              return res.status(200).end()
            }
            next()
          })
          .use(
            trpcApiEndpoint,
            trpcExpress.createExpressMiddleware({
              router: routes, 
              createContext: createContext
            })
          )
      }
    }

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions