Modular Router Thoughts
Hello, I hope I can convey clearly what I hope to accomplish. To start, I have a monorepo, with a few frontends and lots of packages.
some of those packages relate to external services. For instance
@org/asana
and @org/zoom
I have another package, that is my big-ole-router that builds the trpc router and imports all those other packages, builds middlewares to add clients, builds procedures to scope each service.... This was great when I had the router mounted in a mega App I used to have, but now I am making smaller apps with more scoped features....
I don't really want to import the mega router into each app with lots of unneeded procedures. I also don't want to create trpc routers over and over with different combos of middlewares/procedures.....
Is there a nice way to be able to piece-meal a router together with the service specific pieces? Should I attach scoped service routers to difference endpoints?
I don't know the best way to go about solving this problem and I would love some guidance from the community.
Thank you!12 Replies
one way would be to define the procedures without routers
then you can compose them however you want
you can have a flat namespace with a lot of very long proc names in an object and then
router(_.pick(procs, ['getUser, 'createUser', ..]))
I was under the impression that you can only call
initTrpc
once to get your t
and then export the aliases like t.middleware
and t.procedure
... so, with this example, instead of building the zoom stuff in the trpc monorepo package how would I build procedures without routers? When I tried to export t.procedure
or the protectedProcedure
I made with middleware, from my @org/api
and use it in @org/zoom
, I got an error about using something that is instantiating itself. (Sorry, I forget the exact error since I moved on from the other day when I was stuck)But I can't stop thinking about how to make a click-together router where the services can bring their own procedures and middleware
https://discord.com/channels/867764511159091230/1109939580389572728/1111427640394530887
Actually, if I am remembering right... I think I had a cycles issue where
@org/api
can't export protectedProcedure
for @org/asana
to use to create asanaProcedure
because then I would have to import it back in @org/api
. Unless that is what you meant with your reply.... 🤔
I want @org/api
to provide the auth, so I can protect all procedures.....
I'm trying to wrap my head around this all, so can @org/api
init, and create protectedProcedure
and export that. Then any service can import and keep building (no routers yet anywhere!) .... (no cycles yet) then in my actual NextJS app, import both the api
and the service
and build the router there???
Instead of trimming, I did like you suggested. I pulled all the scoped routers
into their service specific package, then removed all the router()
calls and export them as procedures.They are easily exported from their package, and then turned into the router, in the app. I realize now...
@org/api
shouldn't have everythingIt has some local procedures, and imported procedures
looking pretty nice!
what are you using trpc for btw? where do you work? 😄
(sorry, i've been in the matrix with RSC all day - looks like you figured out what you want to do though?)
I am using tRPC with to rapidly build internal apps for my team. We have lots of services we use, but no good birds-eye-view of all our users. I work for https://www.fortunabmc.com/
I use NextJS and tRPC and, for example, make a simple app that ties Azure and Asana together to be able to have a drop-down of users, populated by tRPC and Azure, and then it can create tasks in Asana using info from MsGraph
or maybe we need something with Asana and Zoom, or Salesforce and Dropbox. tRPC has made it so easy to modularize the different clients into procedures, protect it all with Clerk and a middleware. It's so nice to be able to do all of that with type safety
I think I am running into a new issue.... Since
@org/api
created t
with initTRPC
to make my auth middleware to make my protectedProcedure
ok... I imported that into @org/asana
to be able to make asanaProcedure
and this appeared to work... But mutations are failing because a Date
is going through "naked" and failing to parse as JSON. I know you are going to say superjson
and I have it everywhere it should be....
I think since the app
I am building also creates a t
to use in the app, but now there are 2 t
s, one from inside @org/api
and then the other from the app? Is that what is causing it not to transform?
That was it!!! I went ahead and exported t
from @org/api
so that I can use that instance inside the app
to create the final router and it finally works!! You're a great sounding board 🤣I continued on this path and now have slim, composable routers that can be defined per app with just what they need 🙂
Looking great! You could do a blog article about this! ☺