Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tRPC guide (@trpc/server) #2286

Open
xferqr opened this issue Mar 22, 2023 · 5 comments
Open

tRPC guide (@trpc/server) #2286

xferqr opened this issue Mar 22, 2023 · 5 comments

Comments

@xferqr
Copy link

xferqr commented Mar 22, 2023

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
            })
          )
      }
    }
@xferqr
Copy link
Author

xferqr commented Mar 22, 2023

npm package can be used as a sandbox (without use @trpc/client): https://www.npmjs.com/package/trpc-playground

@xferqr
Copy link
Author

xferqr commented Mar 22, 2023

Ts.ED with so many plugins turns into a swiss knife. Thnx for your work @Romakita

@Romakita
Copy link
Collaborator

Hello @xferqr
If you have a time to create a small repository, it'll help developers to understand the usecase between tRpc and Ts.ED .

See you
Romain

@stale
Copy link

stale bot commented Jun 10, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Jun 10, 2023
@stale stale bot removed the wontfix label Jun 24, 2023
@Romakita
Copy link
Collaborator

Maybe create a new page on the documentation could be interesting also @xferqr

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants