Skip to content

Instantly share code, notes, and snippets.

@elmariachi111
Created August 9, 2024 13:40
Show Gist options
  • Save elmariachi111/bd3ef26a5306cec956fbe225a966fb2e to your computer and use it in GitHub Desktop.
Save elmariachi111/bd3ef26a5306cec956fbe225a966fb2e to your computer and use it in GitHub Desktop.
export const DEFAULT_CACHE_SECONDS = 15
/**
* We're **not** using upstash or the Vercel KV SDK here to avoid package conflicts
* instead we're using vercel KV's REST API directly: https://vercel.com/docs/storage/vercel-kv/rest-api
*/
const createClient = <T>({ token, url }: { token: string; url: string }) => {
return {
get: async (key: string): Promise<T | null> => {
const result = await (
await fetch(url, {
body: `["GET", "${key}"]`,
headers: {
Authorization: `Bearer ${token}`,
},
method: 'POST',
})
).json()
if (result.result) {
return JSON.parse(result.result)
} else {
return null
}
},
set: async (
key: string,
value: T,
options: {
ex?: number
},
) => {
const result = await (
await fetch(
`${url}/set/${key}?EX=${options.ex || DEFAULT_CACHE_SECONDS}`,
{
body: JSON.stringify(value),
headers: {
Authorization: `Bearer ${token}`,
},
method: 'POST',
},
)
).json()
return result.result
},
}
}
/**
* @param fetcher Function a function that returns the data to be cached
* @param cacheKey string the cache key
* @param options object
* @param options.ex number the number of seconds to cache the data
*
* @returns Promise<any> the data from the fetcher
* todo: could be generically typed
*/
export const withKVCache = async <T>(
fetcher: () => Promise<T>,
cacheKey: string,
options: { ex: number } = { ex: DEFAULT_CACHE_SECONDS },
) => {
const kvClient =
process.env.KV_REST_API_URL && process.env.KV_REST_API_TOKEN
? createClient<T>({
token: process.env.KV_REST_API_TOKEN,
url: process.env.KV_REST_API_URL,
})
: undefined
if (!kvClient) {
return fetcher()
}
const cacheResult = await kvClient.get(cacheKey)
if (cacheResult) {
// eslint-disable-next-line no-console
console.debug(`[KV_CACHE:HIT] ${cacheKey}`, cacheResult)
return cacheResult
}
const fetchResult = await fetcher()
const kvResult = await kvClient.set(cacheKey, fetchResult, {
ex: options.ex,
})
// eslint-disable-next-line no-console
console.debug(
`[KV_CACHE:MISS] ${cacheKey} [ex:${options.ex}], cached: ${kvResult}`,
)
return fetchResult
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment