trpc
trpc copied to clipboard
feat: Allow middlewares to intercept and override procedure result
Describe the feature you'd like to request
Hi ๐
As I mentioned here, I'm using createCaller with Next.js /app to perform server-side queries. Because Next.js might expect to run multiple queries on page or layout, like generateMetadata and React Server Components, I need to implement a cache of some sort, so that I can deduplicate database calls. To solve this problem, I decided to write a middleware that will cache results from query procedures and add cache instance if I'd need manual control for it (like updating cached results from mutations). If called procedure has cached value, the middleware must return it without calling the actual procedure.
Describe the solution you'd like to see
While technically it is possible to override the result, it'a a bit tricky and not documented: Middleware must return not just the result, but an object assignable to MiddlewareResult type, so I think it need to be simplified. How this might be done:
- Add some helper function, like maybe
overrideResultwhich takes a value fordataproperty and always returnsMiddlewareOKResulttype, like this:
const withCache = t.middleware(({
ctx,
next,
path,
rawInput,
meta,
type,
overrideResut // <- Maybe as part of middleware parameters, so it will borrow same typings as middleware itself?
}) => {
const cached = cache.get({path, rawInput, meta})
if (cached) {
return overrideResult(cached)
}
return next({ctx})
})
- Or make it possible to return just the
datafrom middleware (I think the first variant would be more safe, if tRPC needs data fromMiddlewareResult) - Because
MiddlewareResultis a union ofMiddlewareOKResultandMiddlewareErrorResult, add type guards, so developers can check for specific result type. In my case I need to check if next middleware returnsMiddlewareOKResult, and if so - cache the result. - Document how procedure result can be intercepted and overwritten by middlewares
- Parse and validate the result after all middlewares attached to procedure is called, so that cache might store raw procedure result. In my case, this will allow me to avoid mandatory result validation when I call
cache.revalidatein mutations.
That way middlewares will work similarly to type-graphql middlewares, and I think this case is not the only where result interception and overriding will be useful.
Describe alternate solutions
I checked tRPC documentation and haven't found anything about server-side caching, aside from API Response caching. In my case, I don't use network for procedure calls on server-side, because I don't see why would I need to call the server itself through fetch in the first place. Though Next.js should cache fetch queries by default, so this might be an alternative for someone.
Additional information
As @KATT asked me in the discussion mentioned above, I made an example for my use case, which is mostly consists of the code from my next-app-mikro-orm-trpc-template project.
๐จโ๐งโ๐ฆ Contributing
- [ ] ๐โโ๏ธ Yes, I'd be down to file a PR implementing this feature!