-
Hi everyone 👋 I wonder how suitable this library is for Nest.js? |
Beta Was this translation helpful? Give feedback.
Replies: 18 comments 24 replies
-
Nest does not seem like something you would use with tRPC. How do you see them working together? |
Beta Was this translation helpful? Give feedback.
-
I notice #1511 has been resolved. |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
same, wait :) |
Beta Was this translation helpful? Give feedback.
-
Is there any approximate roadmap? |
Beta Was this translation helpful? Give feedback.
-
None of the maintainers of tRPC are users of nestjs. Therefore, we have no plans on putting in more unpaid work to support nestjs when we have no use of it ourselves - this has to come from the community or through paid consulting. I have no idea what it would take to support nest as I'm not a user of it so I have no insight on how an adapter would look like. |
Beta Was this translation helpful? Give feedback.
-
@KATT said this
Then it occurred to me, nestjs uses express or fastify engines (as per user choice). Trpc already has adapters for express and fastify. So, I guess we just need to figure out a way to hook into the underlying engine with existing trpc adapters. Of course, an example project implementation would be helpful, but this can be a starting point |
Beta Was this translation helpful? Give feedback.
-
I played around with this. I hadn't used trpc before, but I use NestJS. You could sit alongside the API layer of NestJS by creating a trpc router like: const e = express();
const app = await NestFactory.create<NestExpressApplication>(AppModule, new ExpressAdapter(e));
e.use(
'/trpc',
trpcExpress.createExpressMiddleware({
router: appRouter,
}),
);
await app.listen(3000); Which completely sidesteps any NestJS controllers, middleware, etc such as validation using But you can use DI and the module system but I imagine there are some caveats when you want to mess with injection scopes. For example, getting an existing service and hooking that up to your router. const appService = app.get(AppService);
t.router({
hello: t.procedure.query(() => {
return appService.getHello();
}),
}); Before I started, I was thinking it would be nice to keep the NestJS controllers and see if I could pull information like routes, types, and handlers into the trpc router. But you would still lose any middleware, filters, guards, pipes, and interceptors from NestJS (so most of NestJS 😄) . Also, from the trpc docs, it looks like it has its own way of handling those concerns anyway. In the end, I don't see much benefit in combing the two. Maybe find a DI solution for trpc. |
Beta Was this translation helpful? Give feedback.
-
I've recently had some experience with integrating TRPC into a NestJS project. The basic setup looks like this: trpc.service.ts @Injectable()
export class TRPCService {
constructor(
// DI provided by NestJS
@Inject(UserRepo) private readonly userRepo: UserRepo
) {}
// Singleton scope is used for injection by default so `t` is created only once
t = initTRPC.create()
appRouter = this.t.router({
users: this.t.procedure.query(async (opts) => {
// Here we can use providers injected by NestJS in our procedures
return this.userRepo.find()
})
})
applyMiddleware(app: NestExpressApplication) {
app.use(
"/trpc",
createExpressMiddleware({
router: this.appRouter,
})
)
}
} main.ts const app = await NestFactory.create(AppModule)
const trpcService = app.get(TRPCService)
trpcService.applyMiddleware(app) As the project grows trpc-init.service.ts @Injectable()
export class TRCPInitService {
t = initTRPC.create()
} trpc-users.service.ts @Injectable()
export class TRCPUsersService {
usersRouter = this.trpcInit.t.procedure.query(...)
} trpc.service.ts @Injectable()
export class TRCPService {
appRouter = this.trpcInit.t.router({
users: this.trpcUsers.usersRouter
})
} |
Beta Was this translation helpful? Give feedback.
-
hi, how would you use it on the client side? |
Beta Was this translation helpful? Give feedback.
-
Hi, I've built an adapter that will enable you to use tRPC with Nest.JS. have a look at it, and if it gains some traction I'll work on documenting it properly. |
Beta Was this translation helpful? Give feedback.
-
What about using nestia in NestJS? It can generate SDK library and the SDK library can be same thing like |
Beta Was this translation helpful? Give feedback.
-
You coudl try use typedi standalone depdency injection library or only use nest js as depedency injection library |
Beta Was this translation helpful? Give feedback.
-
ts-rest was made specifically for allowing this type of task. Very similar to tRPC |
Beta Was this translation helpful? Give feedback.
-
If someone would like to write typed end-to-end microservices using nestjs, just use following approach, same implemented in trpc using js proxies Gateway side: import type { UsersService } from '@myproject/users-service' // <-- here we just import types, not all
import { InjectClientServiceProxy } from '../decorators'
@Resolver()
export class ExchangeDirectionResolver {
// Please note that `USERS_SERVICE` - is just a token defined in ClientsModule
@InjectClientServiceProxy({ name: "USERS_SERVICE" })
private readonly usersService: UsersService
@Query()
async getUser(@Args() id: string) {
return this.usersService.users.getById(id)
}
} And import { ClientProxy } from '@nestjs/microservices'
import { Inject, HttpException, HttpStatus } from '@nestjs/common'
import DeepProxy from 'proxy-deep'
export const InjectClientServiceProxy =
(options: { name: string }): PropertyDecorator =>
(target, property) => {
const clientProperty = `${String(property)}__client`
Inject(options.name)(target, clientProperty)
let getInstance = () => {} // <-- that might be anti-pattern but I've not found any other solutions to class instance
const proxy = new DeepProxy(
{},
{
get() {
return this.nest(function () {})
},
apply(this, applyTarget, thisArg, args) {
const promise = (getInstance()[clientProperty] as ClientProxy)
.send(this.path.join('.'), args[0])
.toPromise()
return promise
},
}
)
Object.defineProperty(target, property, {
get() {
getInstance = () => {
return this
}
return proxy
},
})
} Microservice side
@Injectable()
@RegisterGlobalServiceContoller() // <-- does some magic
export class UsersService {
@Inject(UserServiceDatabase)
readonly users: UserServiceDatabase // <-- its a simple class with crud
// here might be other data-access service just like `tokenService`, `resetPasswordService` And export const RegisterGlobalServiceContoller =
(): ClassDecorator => (Target) => {
const metadata: { key: string; type: any }[] = Reflect.getMetadata(
PROPERTY_DEPS_METADATA, // <-- imported from nestjs, thanks to nest runtime
Target
)
metadata.forEach((meta) => {
Controller()(meta.type) // <-- make data-access-service a controller else it cant be scanned by nestjs runtime
Object.getOwnPropertyNames(meta.type.prototype).forEach((property) => {
if (property === 'constructor') {
return
}
MessagePattern(`${meta.key}.${property}`)(
meta.type,
property,
Object.getOwnPropertyDescriptor(meta.type.prototype, property)
)
})
})
} Don't forget that you must Troubles
|
Beta Was this translation helpful? Give feedback.
-
Surely possible. Please check a great tutorial from Tom Ray: |
Beta Was this translation helpful? Give feedback.
-
Just going to add that if you're not in need of Nest's DI system you can just bypass it all together by running your own instance of express or fastify and passing it into the Nest.js factory. await fastify.register(fastifyTRPCPlugin as any, {
prefix: "/trpc",
trpcOptions: {
router: appRouter,
createContext: async (opts: CreateFastifyContextOptions) => {
// Init payload
return await trpcInnerContext({
...opts,
prisma,
payload: initializedPayload,
supabase,
revenueCat,
});
},
},
});
const nest = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(fastify as any), // Type conflicts here
); |
Beta Was this translation helpful? Give feedback.
-
sorry but remove this section from your website then; Framework agnostic |
Beta Was this translation helpful? Give feedback.
None of the maintainers of tRPC are users of nestjs.
Therefore, we have no plans on putting in more unpaid work to support nestjs when we have no use of it ourselves - this has to come from the community or through paid consulting.
I have no idea what it would take to support nest as I'm not a user of it so I have no insight on how an adapter would look like.
Update: see potential workaround by @hypnodron below