trpc icon indicating copy to clipboard operation
trpc copied to clipboard

feat: Allow middlewares to intercept and override procedure result

Open octet-stream opened this issue 2 years ago โ€ข 1 comments

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 overrideResult which takes a value for data property and always returns MiddlewareOKResult type, 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 data from middleware (I think the first variant would be more safe, if tRPC needs data from MiddlewareResult)
  • Because MiddlewareResult is a union of MiddlewareOKResult and MiddlewareErrorResult, add type guards, so developers can check for specific result type. In my case I need to check if next middleware returns MiddlewareOKResult, 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.revalidate in 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!

TRP-15

octet-stream avatar Mar 23 '23 15:03 octet-stream