psihoza
psihoza
TTCTheo's Typesafe Cult
Created by Fossil on 4/12/2024 in #questions
How do you cache tRPC server responses w/Next App Router?
So far, what I did... I created a small wrapper for caching db queries:
export const cachedQuery = async <T>(
query: Promise<T>,
keys: string[],
revalidation: { tags: string[]; revalidate: number },
name?: string
) => {
let cacheHit = true
const cached = unstable_cache(
async () => {
cacheHit = false
console.log(`>>>>>>> DB QUERY '${name ?? revalidation.tags[0] ?? 'unknown'}' will run... `)
return await query
},
keys,
revalidation
)

const queryResult = await cached()

if (cacheHit)
console.log(`<><><><><> DB QUERY '${name ?? revalidation.tags[0] ?? 'unknown'}' cache hit!`)

return queryResult
}
export const cachedQuery = async <T>(
query: Promise<T>,
keys: string[],
revalidation: { tags: string[]; revalidate: number },
name?: string
) => {
let cacheHit = true
const cached = unstable_cache(
async () => {
cacheHit = false
console.log(`>>>>>>> DB QUERY '${name ?? revalidation.tags[0] ?? 'unknown'}' will run... `)
return await query
},
keys,
revalidation
)

const queryResult = await cached()

if (cacheHit)
console.log(`<><><><><> DB QUERY '${name ?? revalidation.tags[0] ?? 'unknown'}' cache hit!`)

return queryResult
}
... so my route executes db queries like this:
const keys = ['user', 'getAllUsers']
const revalidation = {
tags: ['user.getAllUsers'],
revalidate: 60 * 60 * 24,
}

return cachedQuery(
ctx.db
.select({
id: users.id,
name: users.name,
})
.from(users),
keys,
revalidation
)
const keys = ['user', 'getAllUsers']
const revalidation = {
tags: ['user.getAllUsers'],
revalidate: 60 * 60 * 24,
}

return cachedQuery(
ctx.db
.select({
id: users.id,
name: users.name,
})
.from(users),
keys,
revalidation
)
This way its realtively easy to change routes, quickly test if it works ok and future changes unstable_cache API should be easier to implement. ... now testing.
4 replies
TTCTheo's Typesafe Cult
Created by Fossil on 4/12/2024 in #questions
How do you cache tRPC server responses w/Next App Router?
I'm banging my head with this for days. You saved me some work on testing Cache-control headers. My worry is is mainly caching database queries, to cut the costs down. I have more than a few that change rarely but are queried by many different users daily. But once I mutate the data, I want to invalidate the cache right away. My second option was to wrap db query in unstable_cache, in trpc router endpoints, then use revalidateTag in mutate endpoints. This seems to work ok, but looks ugly and I'm not sure I want to go that route and spend days refactoring all my endpoints. Also, this caches only db query part of the API response and ideally I want to cache complete response. Last option is beta of Vercel's Data Cache (https://vercel.com/docs/infrastructure/data-cache) but it extends fetch and I dont see how to use it with trpc. A bit frustrated, so close to dumping trpc alltogether. So much more options for regular fetch.
4 replies